﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

// Обработчик события НачалоВыбора поля формы контактной информации.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Форма                - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     Элемент              - ПолеФормы        - элемент формы, содержащий представление контактной информации.
//     Модифицированность   - Булево           - устанавливаемый флаг модифицированности формы.
//     СтандартнаяОбработка - Булево           - устанавливаемый флаг стандартной обработки события формы.
//     ПараметрыОткрытия    - Структура        - параметры открытия формы ввода контактной информации.
//
Процедура НачатьВыбор(Форма, Элемент, Модифицированность = Истина, СтандартнаяОбработка = Ложь, ПараметрыОткрытия = Неопределено) Экспорт
	ПриНачалеВыбора(Форма, Элемент, Модифицированность, СтандартнаяОбработка, ПараметрыОткрытия, Истина);
КонецПроцедуры

// Обработчик события ПриИзменении поля формы контактной информации.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Форма             - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     Элемент           - ПолеФормы        - элемент формы, содержащий представление контактной информации.
//     ЭтоТабличнаяЧасть - Булево           - флаг того, что элемент является частью таблицы формы.
//
Процедура НачатьИзменение(Форма, Элемент, ЭтоТабличнаяЧасть = Ложь) Экспорт
	
	ПриИзмененииКонтактнойИнформации(Форма, Элемент, ЭтоТабличнаяЧасть, Истина, Истина);
	
КонецПроцедуры

// Обработчик события Очистка поля формы контактной информации.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Форма        - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     ИмяРеквизита - Строка           - имя реквизита формы, связанного с представление контактной информации.
//
Процедура НачатьОчистку(Знач Форма, Знач ИмяРеквизита) Экспорт
	ПриОчистке(Форма, ИмяРеквизита, Истина);
КонецПроцедуры

// Обработчик команды, связанной с контактной информацией (написать письмо, открыть адрес, и т.п.).
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Форма      - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     ИмяКоманды - Строка           - имя автоматически сгенерированной команды действия.
//
Процедура НачатьВыполнениеКоманды(Знач Форма, Знач ИмяКоманды) Экспорт
	ПриВыполненииКоманды(Форма, ИмяКоманды, Истина);
КонецПроцедуры

// Обработчик навигационной ссылки для открытия веб-страницы.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//   Форма                - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//   Элемент              - ПолеФормы - элемент формы, содержащий представление контактной информации.
//   НавигационнаяСсылкаФорматированнойСтроки - Строка - значение гиперссылки форматированной строки. Параметр
//                                                       передается по ссылке.
//   СтандартнаяОбработка  - Булево - в данный параметр передается признак выполнения стандартной
//                                системной) обработки события. Если в теле процедуры-обработчика
//                                установить данному параметру значение Ложь, стандартная обработка события
//                                производиться не будет.
//
Процедура НачатьОбработкуНавигационнойСсылки(Форма, Элемент, НавигационнаяСсылкаФорматированнойСтроки, СтандартнаяОбработка) Экспорт
	
	ПриОбработкеНавигационнойСсылки(Форма, Элемент, НавигационнаяСсылкаФорматированнойСтроки, СтандартнаяОбработка, Истина);
	
КонецПроцедуры

// Обработчик навигационной ссылки для открытия веб-страницы.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//   Форма                - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//   Элемент              - ПолеФормы - элемент формы, содержащий представление контактной информации.
//   НавигационнаяСсылкаФорматированнойСтроки - Строка - значение гиперссылки форматированной строки. Параметр
//                                                       передается по ссылке.
//   СтандартнаяОбработка  - Булево - в данный параметр передается признак выполнения стандартной
//                                системной) обработки события. Если в теле процедуры-обработчика
//                                установить данному параметру значение Ложь, стандартная обработка события
//                                производиться не будет.
//
Процедура ОбработкаНавигационнойСсылки(Форма, Элемент, НавигационнаяСсылкаФорматированнойСтроки, СтандартнаяОбработка) Экспорт
	ПриОбработкеНавигационнойСсылки(Форма, Элемент, НавигационнаяСсылкаФорматированнойСтроки, СтандартнаяОбработка, Ложь);
КонецПроцедуры

// Обработчик события АвтоПодбор поля формы контактной информации для подбора вариантов адреса по введенной строке.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Элемент                  - ПолеФормы      - элемент формы, содержащий представление контактной информации.
//     Текст                    - Строка         - строка текста, введенная пользователем в поле контактной информации.
//     ДанныеВыбора             - СписокЗначений - содержит список значений, который будет использован при стандартной
//                                                 обработке события.
//     ПараметрыПолученияДанных - Структура
//                              - Неопределено - содержит параметры поиска, которые будут переданы
//                                в метод ПолучитьДанныеВыбора. Подробнее см. описание расширения поля формы для
//                                поля ввода АвтоПодбор в синтакс-помощнике.
//     Ожидание -   Число       - интервал в секундах после ввода текста, через который произошло событие.
//                                Если 0, то это означает, что событие было вызвано не по поводу ввода текста,
//                                а для формирования списка быстрого выбора. 
//     СтандартнаяОбработка     - Булево         - в данный параметр передается признак выполнения стандартной
//                                системной) обработки события. Если в теле процедуры-обработчика
//                                установить данному параметру значение Ложь, стандартная обработка события
//                                производиться не будет.
//
Процедура АвтоПодборАдреса(Элемент, Текст, ДанныеВыбора, ПараметрыПолученияДанных, Ожидание, СтандартнаяОбработка) Экспорт
	
	Если СтрДлина(Текст) > 2 Тогда
		СтрокаПоиска = Текст;
	ИначеЕсли СтрДлина(Элемент.ТекстРедактирования) > 2 Тогда
		СтрокаПоиска = Элемент.ТекстРедактирования;
	Иначе
		Возврат;
	КонецЕсли;
	
	Если СтрДлина(СтрокаПоиска) > 2 Тогда
		УправлениеКонтактнойИнформациейСлужебныйВызовСервера.АвтоподборАдреса(СтрокаПоиска, ДанныеВыбора);
		Если ТипЗнч(ДанныеВыбора) = Тип("СписокЗначений") Тогда
			СтандартнаяОбработка = (ДанныеВыбора.Количество() = 0);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Обработчик события ОбработкаВыбора поля формы контактной информации.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Форма   - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     ВыбранноеЗначение    - Строка        - выбранное значение, которое будет установлено как значение поля ввода
//                                            контактной информации.
//     ИмяРеквизита         - Строка        - имя реквизита формы, связанного с представление контактной информации.
//     СтандартнаяОбработка - Булево        - в данный параметр передается признак выполнения стандартной
//                                            (системной) обработки события. Если в теле процедуры-обработчика
//                                            установить данному параметру значение Ложь, стандартная обработка события
//                                            производиться не будет.
//
Процедура ОбработкаВыбора(Знач Форма, Знач ВыбранноеЗначение, Знач ИмяРеквизита, СтандартнаяОбработка = Ложь) Экспорт
	
	СтандартнаяОбработка = Ложь;
	Форма[ИмяРеквизита] = ВыбранноеЗначение.Представление;
	
	НайденныеСтроки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(Форма).НайтиСтроки(Новый Структура("ИмяРеквизита", ИмяРеквизита));
	Если НайденныеСтроки.Количество() > 0 Тогда
		НайденныеСтроки[0].Представление = ВыбранноеЗначение.Представление;
		НайденныеСтроки[0].Значение      = ВыбранноеЗначение.Адрес;
	КонецЕсли;
	
КонецПроцедуры

// Открытие формы адреса формы контактной информации.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Форма     - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     Результат - Произвольный     - данные, переданные обработчиком команды.
//
Процедура ОткрытьФормуВводаАдреса(Форма, Результат) Экспорт
	
	Если Результат <> Неопределено Тогда
		Если Результат.Свойство("ЭлементФормыАдреса") Тогда
			НачалоВыбора(Форма, Форма.Элементы[Результат.ЭлементФормыАдреса]);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Обработчик возможного обновления формы контактной информации.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Форма     - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     Результат - Произвольный     - данные, переданные обработчиком команды.
//
Процедура КонтрольОбновленияФормы(Форма, Результат) Экспорт
	
	// Анализ на обратный вызов формы ввода адреса.
	ОткрытьФормуВводаАдреса(Форма, Результат);
	
КонецПроцедуры

// Обработчик события ОбработкаВыбора страны мира. 
// Реализует функционал автоматического заведения элемента справочника СтраныМира после выбора.
//
// Параметры:
//     Элемент              - ПолеФормы    - элемент, содержащий редактируемую страну мира.
//     ВыбранноеЗначение    - Произвольный - значение выбора.
//     СтандартнаяОбработка - Булево       - устанавливаемый флаг стандартной обработки события формы.
//
Процедура СтранаМираОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка) Экспорт
	Если Не СтандартнаяОбработка Тогда 
		Возврат;
	КонецЕсли;
	
	ТипВыбранного = ТипЗнч(ВыбранноеЗначение);
	Если ТипВыбранного = Тип("Массив") Тогда
		СписокПреобразования = Новый Соответствие;
		Для Индекс = 0 По ВыбранноеЗначение.ВГраница() Цикл
			Данные = ВыбранноеЗначение[Индекс];
			Если ТипЗнч(Данные) = Тип("Структура") И Данные.Свойство("Код") Тогда
				СписокПреобразования.Вставить(Индекс, Данные.Код);
			КонецЕсли;
		КонецЦикла;
		
		Если СписокПреобразования.Количество() > 0 Тогда
			УправлениеКонтактнойИнформациейСлужебныйВызовСервера.КоллекцияСтранМираПоДаннымКлассификатора(СписокПреобразования);
			Для Каждого КлючЗначение Из СписокПреобразования Цикл
				ВыбранноеЗначение[КлючЗначение.Ключ] = КлючЗначение.Значение;
			КонецЦикла;
		КонецЕсли;
		
	ИначеЕсли ТипВыбранного = Тип("Структура") И ВыбранноеЗначение.Свойство("Код") Тогда
		ВыбранноеЗначение = УправлениеКонтактнойИнформациейСлужебныйВызовСервера.СтранаМираПоДаннымКлассификатора(ВыбранноеЗначение.Код);
		
	КонецЕсли;
	
КонецПроцедуры

// Конструктор для структуры параметров открытия формы контактной информации.
// Состав полей может быть расширен в общем модуле РаботаСАдресамиКлиент свойствами с национальной спецификой.
//
// Параметры:
//  ВидКонтактнойИнформации  - СправочникСсылка.ВидыКонтактнойИнформации - вид редактируемой контактной информации.
//                           - Структура - см. УправлениеКонтактнойИнформацией.ПараметрыВидаКонтактнойИнформации
//  Значение                 - Строка - сериализованное значение полей контактной информации в формате JSON или XML.
//  Представление            - Строка - представление контактной информации.
//  Комментарий              - Строка - комментарий контактной информации.
//  ТипКонтактнойИнформации  - ПеречислениеСсылка.ТипыКонтактнойИнформации - тип контактной информации.
//                             Если указан, то в возвращаемую структуру добавляются поля соответствующие типу.
// 
// Возвращаемое значение:
//  Структура:
//   * ВидКонтактнойИнформации - см. УправлениеКонтактнойИнформацией.ПараметрыВидаКонтактнойИнформации
//   * ТолькоПросмотр          - Булево - если Истина, то форма будет открыта в режиме только просмотра.
//   * Значение                - Строка - значение полей контактной информации в формате JSON или XML.
//   * Представление           - Строка - представление контактной информации.
//   * ТипКонтактнойИнформации - ПеречислениеСсылка.ТипыКонтактнойИнформации - тип контактной информации, если был указан
//                                                                            в параметрах.
//   * Страна                  - Строка - страна мира, только если указан тип контактной информации Адрес.
//   * Регион                  - Строка - значение поля региона, только если указан тип контактной информации Адрес.
//                                       Актуально для стран ЕАЭС.
//   * Индекс                  - Строка - почтовый индекс, только если указан тип контактной информации Адрес.
//   * ТипПомещения            - Строка - тип помещения в форме ввода нового адреса, , только если указан тип контактной
//                                       информации Адрес.
//   * КодСтраны               - Строка - телефонный код страны мира, только если указан тип контактной информации Телефон.
//   * КодГорода               - Строка - телефонный код города, только если указан тип контактной информации Телефон.
//   * НомерТелефона           - Строка - телефонный номер, только если указан тип контактной информации Телефон.
//   * Добавочный              - Строка - добавочный телефонный номер, только если указан тип контактной информации Телефон.
//   * Заголовок               - Строка - заголовок формы. По умолчанию, представление вида контактной информации.
//   * ТипАдреса               - Строка - варианты: Пустая строка (по умолчанию), "ВСвободнойФорме", "ЕАЭС";
//                                       Для РФ: "Муниципальный" или "АдминистративноТерриториальный".
//                                       Если не указан (пустая строка), то для существующего адреса будет установлен адрес
//                                       выбранный пользователем в форме ввода адреса, для нового адреса - Муниципальный".
//
Функция ПараметрыФормыКонтактнойИнформации(ВидКонтактнойИнформации, Значение,
	Представление = Неопределено, Комментарий = Неопределено, ТипКонтактнойИнформации = Неопределено) Экспорт
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("ВидКонтактнойИнформации", ВидКонтактнойИнформации);
	ПараметрыФормы.Вставить("ТолькоПросмотр", Ложь);
	ПараметрыФормы.Вставить("Значение", Значение);
	ПараметрыФормы.Вставить("Представление", Представление);
	ПараметрыФормы.Вставить("Комментарий", Комментарий);
	ПараметрыФормы.Вставить("ТипАдреса", "");
	Если ТипКонтактнойИнформации <> Неопределено Тогда
		ПараметрыФормы.Вставить("ТипКонтактнойИнформации", ТипКонтактнойИнформации);
		Если ТипКонтактнойИнформации = ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес") Тогда
			ПараметрыФормы.Вставить("Страна");
			ПараметрыФормы.Вставить("Регион");
			ПараметрыФормы.Вставить("Индекс");
			ПараметрыФормы.Вставить("ТипПомещения", "Квартира");
		ИначеЕсли ТипКонтактнойИнформации = ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Телефон") Тогда
			ПараметрыФормы.Вставить("КодСтраны");
			ПараметрыФормы.Вставить("КодГорода");
			ПараметрыФормы.Вставить("НомерТелефона");
			ПараметрыФормы.Вставить("Добавочный");
		КонецЕсли;
	КонецЕсли;
	
	Если ТипЗнч(ВидКонтактнойИнформации) = Тип("Структура") И ВидКонтактнойИнформации.Свойство("Наименование") Тогда
		ПараметрыФормы.Вставить("Заголовок", ВидКонтактнойИнформации.Наименование);
	Иначе
		ПараметрыФормы.Вставить("Заголовок", Строка(ВидКонтактнойИнформации));
	КонецЕсли;
	
	Возврат ПараметрыФормы;
	
КонецФункции

// Открывает подходящую форму контактной информации для редактирования или просмотра.
//
//  Параметры:
//      Параметры    - Произвольный - результат функции ПараметрыФормыКонтактнойИнформации.
//      Владелец     - Произвольный - параметр для открываемой формы.
//      Оповещение   - ОписаниеОповещения - для обработки закрытия формы.
//
//  Возвращаемое значение:
//   ФормаКлиентскогоПриложения - необходимая форма.
//
Функция ОткрытьФормуКонтактнойИнформации(Параметры, Владелец = Неопределено, Оповещение = Неопределено) Экспорт
	Параметры.Вставить("ОткрытаПоСценарию", Истина);
	Возврат ОткрытьФорму("Обработка.ВводКонтактнойИнформации.Форма", Параметры, Владелец,,,, Оповещение);
КонецФункции

// Создает письмо по контактной информации.
//
// Параметры:
//  ЗначенияПолей - Строка
//                - Структура
//                - Соответствие
//                - СписокЗначений - значение контактной информации.
//  Представление - Строка - представление контактной информации. Используется, если невозможно определить 
//                              представление из параметра. ЗначенияПолей (отсутствие поля Представление).
//  ОжидаемыйВид  - СправочникСсылка.ВидыКонтактнойИнформации
//                - ПеречислениеСсылка.ТипыКонтактнойИнформации
//                - Структура - используется для определения типа, если его невозможно вычислить по полю ЗначенияПолей.
//  ИсточникКонтактнойИнформации - Произвольный - объект владелец контактной информации.
//  ИмяРеквизита  - Строка
//
Процедура СоздатьЭлектронноеПисьмо(Знач ЗначенияПолей, Знач Представление = "", ОжидаемыйВид = Неопределено, ИсточникКонтактнойИнформации = Неопределено, ИмяРеквизита = "") Экспорт
	
	АдресПочты = "";
	Если ЗначениеЗаполнено(Представление) Тогда
		
		Если ОбщегоНазначенияКлиентСервер.АдресЭлектроннойПочтыСоответствуетТребованиям(Представление, Истина) Тогда
			АдресПочты = Представление;
		КонецЕсли;
		
	КонецЕсли;
	
	Если ПустаяСтрока(АдресПочты) Тогда
		
		ОписаниеКонтактнойИнформации = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформации(
			ЗначенияПолей, Представление, ОжидаемыйВид);
		
		КонтактнаяИнформация = УправлениеКонтактнойИнформациейСлужебныйВызовСервера.ПривестиКонтактнуюИнформациюXML(ОписаниеКонтактнойИнформации);
		
		Если ЗначениеЗаполнено( КонтактнаяИнформация.Представление) Тогда
			АдресПочты = КонтактнаяИнформация.Представление;
		Иначе
			АдресПочты = УправлениеКонтактнойИнформациейСлужебныйВызовСервера.СтрокаСоставаКонтактнойИнформации(КонтактнаяИнформация.ДанныеXML);
		КонецЕсли;
		
		ТекстОшибки = "";
		ТипИнформации = КонтактнаяИнформация.ТипКонтактнойИнформации;
		Если ПустаяСтрока(АдресПочты) 
		  Или Не ОбщегоНазначенияКлиентСервер.АдресЭлектроннойПочтыСоответствуетТребованиям(Представление, Истина) Тогда
			ТекстОшибки= НСтр("ru = 'Для отправки письма введите адрес электронной почты.'");
		ИначеЕсли ТипЗнч(АдресПочты) <> Тип("Строка") Или ТипИнформации = Неопределено Тогда
			ТекстОшибки =  НСтр("ru = 'Ошибка получения адреса электронной почты, неверный тип контактной информации'");
		ИначеЕсли ТипИнформации <> ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты") Тогда
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Нельзя создать письмо по контактной информацию с типом ""%1""'"), ТипИнформации);
		КонецЕсли;
		
		Если ЗначениеЗаполнено(ТекстОшибки) Тогда
			Если ЗначениеЗаполнено(ИмяРеквизита) Тогда
				ОбщегоНазначенияКлиент.СообщитьПользователю(ТекстОшибки,, ИмяРеквизита);
			Иначе
				ПоказатьПредупреждение(, ТекстОшибки );
			КонецЕсли;
			Возврат
		КонецЕсли;
		
	КонецЕсли;
	
	Если ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСПочтовымиСообщениями") Тогда
		МодульРаботаСПочтовымиСообщениямиКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("РаботаСПочтовымиСообщениямиКлиент");
		
		Получатель = Новый Массив;
		Получатель.Добавить(Новый Структура("Адрес, Представление, ИсточникКонтактнойИнформации", 
			АдресПочты, СтрЗаменить(Строка(ИсточникКонтактнойИнформации), ",", ""), ИсточникКонтактнойИнформации));
		ПараметрыОтправки = Новый Структура("Получатель", Получатель);
		МодульРаботаСПочтовымиСообщениямиКлиент.СоздатьНовоеПисьмо(ПараметрыОтправки);
	Иначе
		ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку("mailto:" + АдресПочты);
	КонецЕсли;
	
КонецПроцедуры

// Создает письмо по контактной информации.
//
// Параметры:
//  ЗначенияПолей                - Строка
//                               - Структура
//                               - Соответствие
//                               - СписокЗначений - контактная информация.
//  Представление                - Строка - представление. Используется, если невозможно определить представление из параметра.
//                                           ЗначенияПолей (отсутствие поля Представление).
//  ОжидаемыйВид                 - СправочникСсылка.ВидыКонтактнойИнформации
//                               - ПеречислениеСсылка.ТипыКонтактнойИнформации
//                               - Структура - используется для определения типа, если его невозможно вычислить по полю
//                                             ЗначенияПолей.
//  ИсточникКонтактнойИнформации - ЛюбаяСсылка - объект который является источником контактной информации.
//
Процедура СоздатьSMS(Знач ЗначенияПолей, Знач Представление = "", ОжидаемыйВид = Неопределено, ИсточникКонтактнойИнформации = "") Экспорт
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ОтправкаSMS") Тогда
		ВызватьИсключение НСтр("ru = 'Отправка SMS недоступна.'");
	КонецЕсли;
	
	НомерПолучателя = "";
	
	Если ПустаяСтрока(Представление) Тогда
		
		КонтактнаяИнформация = УправлениеКонтактнойИнформациейСлужебныйВызовСервера.ПривестиКонтактнуюИнформациюXML(
			Новый Структура("ЗначенияПолей, Представление, ВидКонтактнойИнформации", ЗначенияПолей, Представление, ОжидаемыйВид));
		
		ТипИнформации = КонтактнаяИнформация.ТипКонтактнойИнформации;
		Если ТипИнформации <> ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Телефон") Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Нельзя отправить SMS по контактной информацию с типом ""%1""'"), ТипИнформации);
		КонецЕсли;
		
		Если ЗначенияПолей = "" И ПустаяСтрока(Представление) Тогда
			ПоказатьПредупреждение(, НСтр("ru = 'Для отправки SMS введите номер телефона.'"));
			Возврат;
		КонецЕсли;
		
		XMLДанные = КонтактнаяИнформация.ДанныеXML;
		Если ЗначениеЗаполнено(XMLДанные) Тогда
			НомерПолучателя = УправлениеКонтактнойИнформациейСлужебныйВызовСервера.СтрокаСоставаКонтактнойИнформации(XMLДанные);
		КонецЕсли;
	
	КонецЕсли;
	
	Если ПустаяСтрока(НомерПолучателя) Тогда
		НомерПолучателя = СокрЛП(Представление);
	КонецЕсли;
	
	#Если МобильныйКлиент Тогда
		Сообщение = Новый SMSСообщение();
		Сообщение.Получатели.Добавить(НомерПолучателя);
		СредстваТелефонии.ПослатьSMS(Сообщение, Истина);
		Возврат;
	#КонецЕсли
	
	СведенияОПолучателе = Новый Структура();
	СведенияОПолучателе.Вставить("Телефон",                      НомерПолучателя);
	СведенияОПолучателе.Вставить("Представление",                Строка(ИсточникКонтактнойИнформации));
	СведенияОПолучателе.Вставить("ИсточникКонтактнойИнформации", ИсточникКонтактнойИнформации);
	
	НомераПолучателей = Новый Массив;
	НомераПолучателей.Добавить(СведенияОПолучателе);
	
	МодульОтправкаSMSКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ОтправкаSMSКлиент");
	МодульОтправкаSMSКлиент.ОтправитьSMS(НомераПолучателей, "", Новый Структура("ПеревестиВТранслит", Ложь));
	
КонецПроцедуры

// Совершает звонок на переданный номер телефона по SIP телефонии,
// а если она не доступна, то с использованием программы Skype.
//
// Параметры:
//  НомерТелефона -Строка - номер телефона, на который будет осуществлен звонок.
//
Процедура ПозвонитьПоТелефону(НомерТелефона) Экспорт
	
	НомерТелефона = СтроковыеФункцииКлиентСервер.ЗаменитьОдниСимволыДругими("()_- ", НомерТелефона, "");
	
	ИмяПротокола = "tel"; // по умолчанию используем "tel".
	
	#Если МобильныйКлиент Тогда
		СредстваТелефонии.НабратьНомер(НомерТелефона, Истина);
		Возврат;
	#КонецЕсли
	
	#Если НЕ ВебКлиент Тогда
		ДоступноеИмяПротокола = ПрограммаТелефонииУстановлена();
		Если ДоступноеИмяПротокола = Неопределено Тогда
			СтрокаСПредупреждением = Новый ФорматированнаяСтрока(
					НСтр("ru = 'Для совершения звонка установите программу телефонии, например'"),
					 " ", Новый ФорматированнаяСтрока("Skype",,,, "http://www.skype.com"), ".");
			ПоказатьПредупреждение(Неопределено, СтрокаСПредупреждением);
			Возврат;
		ИначеЕсли НЕ ПустаяСтрока(ДоступноеИмяПротокола) Тогда
			ИмяПротокола = ДоступноеИмяПротокола;
		КонецЕсли;
	#КонецЕсли
	
	СтрокаЗапуска = ИмяПротокола + ":" + НомерТелефона;
	
	Оповещение = Новый ОписаниеОповещения("ПослеЗапускаПриложения", ЭтотОбъект);
	ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку(СтрокаЗапуска, Оповещение);
	
КонецПроцедуры

// Совершает звонок в программе Skype.
//
// Параметры:
//  ЛогинSkype - Строка - логин Skype.
//
Процедура ПозвонитьНаSkype(ЛогинSkype) Экспорт
	
	ОткрытьSkype("skype:" + ЛогинSkype + "?call");

КонецПроцедуры

// Открыть окно беседы(чат) в программе Skype
//
// Параметры:
//  ЛогинSkype - Строка - логин Skype.
//
Процедура НачатьБеседуВSkype(ЛогинSkype) Экспорт
	
	ОткрытьSkype("skype:" + ЛогинSkype + "?chat");
	
КонецПроцедуры

// Открывает ссылку по контактной информации.
//
// Параметры:
//  ЗначенияПолей - Строка
//                - Структура
//                - Соответствие
//                - СписокЗначений - контактная информация.
//  Представление - Строка - представление. Используется, если невозможно определить представление из параметра.
//                            ЗначенияПолей (отсутствие поля "Представление").
//  ОжидаемыйВид  - СправочникСсылка.ВидыКонтактнойИнформации
//                - ПеречислениеСсылка.ТипыКонтактнойИнформации
//                - Структура -
//                      Используется для определения типа, если его невозможно вычислить по полю ЗначенияПолей.
//
Процедура ПерейтиПоВебСсылке(Знач ЗначенияПолей, Знач Представление = "", ОжидаемыйВид = Неопределено) Экспорт
	
	Если ОжидаемыйВид = Неопределено Тогда
		ОжидаемыйВид = ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.ВебСтраница");
	КонецЕсли;
	
	КонтактнаяИнформация = УправлениеКонтактнойИнформациейСлужебныйВызовСервера.ПривестиКонтактнуюИнформациюXML(
		Новый Структура("ЗначенияПолей, Представление, ВидКонтактнойИнформации", ЗначенияПолей, Представление, ОжидаемыйВид));
	ТипИнформации = КонтактнаяИнформация.ТипКонтактнойИнформации;
	
	Если ТипИнформации <> ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.ВебСтраница") Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Нельзя открыть ссылку по контактной информации с типом ""%1""'"), ТипИнформации);
	КонецЕсли;
		
	XMLДанные = КонтактнаяИнформация.ДанныеXML;

	АдресСсылки = УправлениеКонтактнойИнформациейСлужебныйВызовСервера.СтрокаСоставаКонтактнойИнформации(XMLДанные);
	Если ТипЗнч(АдресСсылки) <> Тип("Строка") Тогда
		ВызватьИсключение НСтр("ru = 'Ошибка получения ссылки, неверный тип контактной информации'");
	КонецЕсли;
	
	Если СтрНайти(АдресСсылки, "://") > 0 Тогда
		ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку(АдресСсылки);
	Иначе
		ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку("http://" + АдресСсылки);
	КонецЕсли;
КонецПроцедуры

// Показывает адрес в браузере на картах Яндекс или Google.
//
// Параметры:
//  Адрес                       - Строка - текстовое представление адреса.
//  ИмяКартографическогоСервиса - Строка - имя картографического сервиса, в котором необходимо показать адрес:
//                                         Яндекс.Карты или GoogleMaps.
//
Процедура ПоказатьАдресНаКарте(Адрес, ИмяКартографическогоСервиса) Экспорт
	АдресКодированный = ДекодированиеСтроки(Адрес);
	Если ИмяКартографическогоСервиса = "GoogleMaps" Тогда
		СтрокаЗапуска = "https://maps.google.com/?q=" + АдресКодированный;
	Иначе
		СтрокаЗапуска = "https://maps.yandex.com/?text=" + АдресКодированный;
	КонецЕсли;
	
	ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку(СтрокаЗапуска);
	
КонецПроцедуры

// Отображает форму с историей изменения контактной информации.
//
// Параметры:
//  Форма                         - ФормаКлиентскогоПриложения - форма с контактной информацией.
//  ПараметрыКонтактнойИнформации - Структура - сведения об элементе контактной информации.
//  АсинхронныйВызов              - Булево - служебный параметр.
//
Процедура ОткрытьФормуИсторииИзменений(Форма, ПараметрыКонтактнойИнформации, АсинхронныйВызов = Ложь) Экспорт
	
	Результат = Новый Структура("Вид", ПараметрыКонтактнойИнформации.Вид);
	НайденныеСтроки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(Форма).НайтиСтроки(Результат);
	
	СписокКонтактнойИнформации = Новый Массив;
	Для каждого СтрокаКонтактнойИнформации Из НайденныеСтроки Цикл
		КонтактнаяИнформация = Новый Структура("Представление, Значение, ЗначенияПолей, ДействуетС, Комментарий");
		ЗаполнитьЗначенияСвойств(КонтактнаяИнформация, СтрокаКонтактнойИнформации);
		СписокКонтактнойИнформации.Добавить(КонтактнаяИнформация);
	КонецЦикла;
	
	ДополнительныеПараметры = ПослеЗакрытияФормыИсторииДополнительныеПараметры(Форма, ПараметрыКонтактнойИнформации, АсинхронныйВызов);
	
	ПараметрыФормы = Новый Структура("СписокКонтактнойИнформации", СписокКонтактнойИнформации);
	ПараметрыФормы.Вставить("ВидКонтактнойИнформации", ПараметрыКонтактнойИнформации.Вид);
	ПараметрыФормы.Вставить("ТолькоПросмотр", Форма.ТолькоПросмотр);
	
	ОповещениеОЗакрытие = Новый ОписаниеОповещения("ПослеЗакрытияФормыИстории", УправлениеКонтактнойИнформациейКлиент, ДополнительныеПараметры);
	
	ОткрытьФорму("Обработка.ВводКонтактнойИнформации.Форма.ИсторияКонтактнойИнформации", ПараметрыФормы, Форма,,,, ОповещениеОЗакрытие);
	
КонецПроцедуры

// Синхронные обработчики

// Обработчик события НачалоВыбора поля формы контактной информации.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Форма                - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     Элемент              - ПолеФормы        - элемент формы, содержащий представление контактной информации.
//     Модифицированность   - Булево           - устанавливаемый флаг модифицированности формы.
//     СтандартнаяОбработка - Булево           - устанавливаемый флаг стандартной обработки события формы.
//     ПараметрыОткрытия    - Структура        - параметры открытия формы ввода контактной информации.
//
Процедура НачалоВыбора(Форма, Элемент, Модифицированность = Истина, СтандартнаяОбработка = Ложь, ПараметрыОткрытия = Неопределено) Экспорт
	ПриНачалеВыбора(Форма, Элемент, Модифицированность, СтандартнаяОбработка, ПараметрыОткрытия, Ложь);
КонецПроцедуры

// Обработчик события Очистка поля формы контактной информации.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Форма        - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     ИмяРеквизита - Строка           - имя реквизита формы, связанного с представление контактной информации.
//
Процедура Очистка(Знач Форма, Знач ИмяРеквизита) Экспорт
	ПриОчистке(Форма, ИмяРеквизита, Ложь);
КонецПроцедуры

// Обработчик команды, связанной с контактной информацией (написать письмо, открыть адрес, и т.п.).
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Форма      - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     ИмяКоманды - Строка           - имя автоматически сгенерированной команды действия.
//
Процедура ВыполнитьКоманду(Знач Форма, Знач ИмяКоманды) Экспорт
	ПриВыполненииКоманды(Форма, ИмяКоманды, Ложь);
КонецПроцедуры

// Обработчик события ПриИзменении поля формы контактной информации.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Форма             - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     Элемент           - ПолеФормы        - элемент формы, содержащий представление контактной информации.
//     ЭтоТабличнаяЧасть - Булево           - флаг того, что элемент является частью таблицы формы.
//
Процедура ПриИзменении(Форма, Элемент, ЭтоТабличнаяЧасть = Ложь) Экспорт
	
	ПриИзмененииКонтактнойИнформации(Форма, Элемент, ЭтоТабличнаяЧасть, Истина, Ложь);
	
КонецПроцедуры

#Область УстаревшиеПроцедурыИФункции

// Устарела. Следует использовать АвтоПодборАдреса.
// Обработчик события АвтоПодбор поля формы контактной информации.
// Вызывается из подключаемых действий при внедрении подсистемы "Контактная информация".
//
// Параметры:
//     Текст                - Строка         - строка текста, введенная пользователем в поле контактной информации.
//     ДанныеВыбора         - СписокЗначений - содержит список значений, который будет использован при стандартной
//                                             обработке события.
//     СтандартнаяОбработка - Булево         - в данный параметр передается признак выполнения стандартной
//                                             (системной) обработки события. Если в теле процедуры-обработчика
//                                             установить данному параметру значение Ложь, стандартная обработка события
//                                             производиться не будет.
//
Процедура АвтоПодбор(Знач Текст, ДанныеВыбора, СтандартнаяОбработка = Ложь) Экспорт
	
	Если СтрДлина(Текст) > 2 Тогда
		АвтоПодборАдреса(Неопределено, Текст, ДанныеВыбора, Неопределено, 0, СтандартнаяОбработка);
	КонецЕсли;
	
КонецПроцедуры

// Устарела. Следует использовать ПриИзменении.
//
// Параметры:
//     Форма             - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     Элемент           - ПолеФормы        - элемент формы, содержащий представление контактной информации.
//     ЭтоТабличнаяЧасть - Булево           - флаг того, что элемент является частью таблицы формы.
//
Процедура ПредставлениеПриИзменении(Форма, Элемент, ЭтоТабличнаяЧасть = Ложь) Экспорт
	ПриИзменении(Форма, Элемент, ЭтоТабличнаяЧасть);
КонецПроцедуры

// Устарела. Следует использовать НачалоВыбора.
//
// Параметры:
//     Форма                - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     Элемент              - ПолеФормы        - элемент формы, содержащий представление контактной информации.
//     Модифицированность   - Булево           - устанавливаемый флаг модифицированности формы.
//     СтандартнаяОбработка - Булево           - устанавливаемый флаг стандартной обработки события формы.
//
// Возвращаемое значение:
//  Неопределено - не используется, обратная совместимость.
//
Функция ПредставлениеНачалоВыбора(Форма, Элемент, Модифицированность = Истина, СтандартнаяОбработка = Ложь) Экспорт
	НачалоВыбора(Форма, Элемент, Модифицированность, СтандартнаяОбработка);
	Возврат Неопределено;
КонецФункции

// Устарела. Следует использовать Очистка.
//
// Параметры:
//     Форма        - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     ИмяРеквизита - Строка           - имя реквизита формы, связанного с представление контактной информации.
//
// Возвращаемое значение:
//  Неопределено - не используется, обратная совместимость.
//
Функция ПредставлениеОчистка(Форма, ИмяРеквизита) Экспорт
	Очистка(Форма, ИмяРеквизита);
	Возврат Неопределено;
КонецФункции

// Устарела. Следует использовать ВыполнитьКоманду.
//
// Параметры:
//     Форма      - ФормаКлиентскогоПриложения - форма владельца контактной информации.
//     ИмяКоманды - Строка           - имя автоматически сгенерированной команды действия.
//
// Возвращаемое значение:
//  Неопределено - не используется, обратная совместимость.
//
Функция ПодключаемаяКоманда(Форма, ИмяКоманды) Экспорт
	ВыполнитьКоманду(Форма, ИмяКоманды);
	Возврат Неопределено;
КонецФункции

#КонецОбласти

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

// Завершение немодальных диалогов.

// Обработчик после закрытия формы истории 
// 
// Параметры:
//   Результат - Структура
//   ДополнительныеПараметры - см. ПослеЗакрытияФормыИсторииДополнительныеПараметры
//
Процедура ПослеЗакрытияФормыИстории(Результат, ДополнительныеПараметры) Экспорт
	
	Если Результат = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Форма = ДополнительныеПараметры.Форма;
	
	Отбор = Новый Структура("Вид", ДополнительныеПараметры.Вид);
	НайденныеСтроки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(Форма).НайтиСтроки(Отбор);
	
	СтарыйКомментарий = Неопределено;
	Для каждого СтрокаКонтактнойИнформации Из НайденныеСтроки Цикл
		Если НЕ СтрокаКонтактнойИнформации.ЭтоИсторическаяКонтактнаяИнформация Тогда
			СтарыйКомментарий = СтрокаКонтактнойИнформации.Комментарий;
		КонецЕсли;
		УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(Форма).Удалить(СтрокаКонтактнойИнформации);
	КонецЦикла;
	
	ПараметрыОбновления = Новый Структура;
	Для Каждого СтрокаКонтактнойИнформации Из Результат.История Цикл
		ДанныеСтроки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(Форма).Добавить();
		ЗаполнитьЗначенияСвойств(ДанныеСтроки, СтрокаКонтактнойИнформации);
		Если НЕ СтрокаКонтактнойИнформации.ЭтоИсторическаяКонтактнаяИнформация Тогда
			Если ПустаяСтрока(СтрокаКонтактнойИнформации.Представление)
				И Результат.Свойство("ВидРедактирования")
				И Результат.ВидРедактирования = "Диалог" Тогда
					Представление = УправлениеКонтактнойИнформациейКлиентСервер.ТекстПустогоАдресаВВидеГиперссылки();
			Иначе
				Представление = СтрокаКонтактнойИнформации.Представление;
			КонецЕсли;
			Форма[ДополнительныеПараметры.ИмяЭлемента] = Представление;
			ДанныеСтроки.ИмяРеквизита = ДополнительныеПараметры.ИмяЭлемента;
			ДанныеСтроки.ИмяЭлементаДляРазмещения = ДополнительныеПараметры.ИмяЭлементаДляРазмещения;
			Если ДанныеСтроки.Комментарий <> СтарыйКомментарий Тогда
				ПараметрыОбновления.Вставить("ЭтоДобавлениеКомментария", Истина);
				ПараметрыОбновления.Вставить("ИмяЭлементаДляРазмещения", ДополнительныеПараметры.ИмяЭлементаДляРазмещения);
				ПараметрыОбновления.Вставить("ИмяРеквизита", ДополнительныеПараметры.ИмяЭлемента);
				ПараметрыОбновления.Вставить("ТипКонтактнойИнформации", СтрокаКонтактнойИнформации.Тип);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Форма.Модифицированность = Истина;
	Если ЗначениеЗаполнено(ПараметрыОбновления) Тогда
		ОбновитьКонтактнуюИнформациюФормы(Форма, ПараметрыОбновления, ДополнительныеПараметры.АсинхронныйВызов);
	КонецЕсли;
КонецПроцедуры

// Обработчик после закрытия формы списка справочника ВидыКонтактнойИнформации с отбором по владельцу контактной информации
// 
// Параметры:
//   Результат - Структура
//             - Неопределено
//   ДополнительныеПараметры - Структура:
//     * Форма                    - ФормаКлиентскогоПриложения
//     * ИмяЭлементаДляРазмещения - Строка
//     * АсинхронныйВызов         - Булево
//
Процедура ПослеЗакрытияФормыСпискаВидыКонтактнойИнформации(Результат, ДополнительныеПараметры) Экспорт

	Форма = ДополнительныеПараметры.Форма;
	ПараметрыОбновления = Новый Структура;
	ПараметрыОбновления.Вставить("Перечитать", Истина);
	ПараметрыОбновления.Вставить("ИмяЭлементаДляРазмещения", ДополнительныеПараметры.ИмяЭлементаДляРазмещения);
	ОбновитьКонтактнуюИнформациюФормы(Форма, ПараметрыОбновления, ДополнительныеПараметры.АсинхронныйВызов);
	
КонецПроцедуры

// Продолжение вызова ПредставлениеНачалоВыбора 
// 
// Параметры:
//   РезультатЗакрытия - Структура
//   ДополнительныеПараметры - см. ПредставлениеНачалоВыбораЗавершениеДополнительныеПараметры
// 
Процедура ПредставлениеНачалоВыбораЗавершение(Знач РезультатЗакрытия, Знач ДополнительныеПараметры) Экспорт
	
	Если ТипЗнч(РезультатЗакрытия) <> Тип("Структура") Тогда
		Если ДополнительныеПараметры.Свойство("ОбновитьКонтекстноеМеню") 
			И ДополнительныеПараметры.ОбновитьКонтекстноеМеню Тогда
				Результат = Новый Структура();
				Результат.Вставить("ОбновитьКонтекстноеМеню",  Истина);
				Результат.Вставить("ИмяЭлементаДляРазмещения", ДополнительныеПараметры.ИмяЭлементаРазмещения);
				ОбновитьКонтактнуюИнформациюФормы(ДополнительныеПараметры.Форма, Результат, ДополнительныеПараметры.АсинхронныйВызов);
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	ДанныеЗаполнения = ДополнительныеПараметры.ДанныеЗаполнения;
	ДанныеНаФорме    = ДополнительныеПараметры.ДанныеСтроки;
	Результат        = ДополнительныеПараметры.Результат;
	Элемент          = ДополнительныеПараметры.Элемент;
	Форма            = ДополнительныеПараметры.Форма;
	
	ТекстПредставления = РезультатЗакрытия.Представление;
	Комментарий        = РезультатЗакрытия.Комментарий;
	
	Если ДанныеНаФорме.Свойство("ХранитьИсториюИзменений") И ДанныеНаФорме.ХранитьИсториюИзменений Тогда
		КонтактнаяИнформацияОписаниеДополнительныхРеквизитов = ДанныеЗаполнения.КонтактнаяИнформацияОписаниеДополнительныхРеквизитов;
		Отбор = Новый Структура("Вид", ДанныеНаФорме.Вид);
		НайденныеСтроки = КонтактнаяИнформацияОписаниеДополнительныхРеквизитов.НайтиСтроки(Отбор);
		Для Каждого СтрокаКонтактнойИнформации Из НайденныеСтроки Цикл
			КонтактнаяИнформацияОписаниеДополнительныхРеквизитов.Удалить(СтрокаКонтактнойИнформации);
		КонецЦикла;
		
		Отбор = Новый Структура("Вид", ДанныеНаФорме.Вид);
		НайденныеСтроки = РезультатЗакрытия.КонтактнаяИнформацияОписаниеДополнительныхРеквизитов.НайтиСтроки(Отбор);
		
		Если НайденныеСтроки.Количество() > 1 Тогда
			
			СтрокаСДействующимАдресом = Неопределено;
			МинимальнаяДата = Неопределено;
			
			Для Каждого СтрокаКонтактнойИнформации Из НайденныеСтроки Цикл
				
				НоваяКонтактнаяИнформация = КонтактнаяИнформацияОписаниеДополнительныхРеквизитов.Добавить();
				ЗаполнитьЗначенияСвойств(НоваяКонтактнаяИнформация, СтрокаКонтактнойИнформации);
				НоваяКонтактнаяИнформация.ИмяЭлементаДляРазмещения = ДополнительныеПараметры.ИмяЭлементаРазмещения;
				
				Если СтрокаСДействующимАдресом = Неопределено
					ИЛИ СтрокаКонтактнойИнформации.ДействуетС > СтрокаСДействующимАдресом.ДействуетС Тогда
						СтрокаСДействующимАдресом = СтрокаКонтактнойИнформации;
				КонецЕсли;
				Если МинимальнаяДата = Неопределено
					ИЛИ СтрокаКонтактнойИнформации.ДействуетС < МинимальнаяДата Тогда
						МинимальнаяДата = СтрокаКонтактнойИнформации.ДействуетС;
				КонецЕсли;
				
			КонецЦикла;
			
			// Исправление некорректных адресов, без первоначальной даты заполнения
			Если ЗначениеЗаполнено(МинимальнаяДата) Тогда
				Отбор = Новый Структура("ДействуетС", МинимальнаяДата);
				СтрокиСМинимальнойДатой = КонтактнаяИнформацияОписаниеДополнительныхРеквизитов.НайтиСтроки(Отбор);
				Если СтрокиСМинимальнойДатой.Количество() > 0 Тогда
					СтрокиСМинимальнойДатой[0].ДействуетС = Дата(1, 1, 1);
				КонецЕсли;
			КонецЕсли;
			
			Если СтрокаСДействующимАдресом <> Неопределено Тогда
				ТекстПредставления = СтрокаСДействующимАдресом.Представление;
				Комментарий        = СтрокаСДействующимАдресом.Комментарий;
			КонецЕсли;
			
		ИначеЕсли НайденныеСтроки.Количество() = 1 Тогда
			НоваяКонтактнаяИнформация = КонтактнаяИнформацияОписаниеДополнительныхРеквизитов.Добавить();
			ЗаполнитьЗначенияСвойств(НоваяКонтактнаяИнформация, НайденныеСтроки[0],, "ДействуетС");
			НоваяКонтактнаяИнформация.ИмяЭлементаДляРазмещения = ДополнительныеПараметры.ИмяЭлементаРазмещения;
			ДанныеНаФорме.ДействуетС = Дата(1, 1, 1);
		КонецЕсли;
		
	КонецЕсли;
	
	Если ДополнительныеПараметры.ЭтоТабличнаяЧасть Тогда
		ДанныеЗаполнения[Элемент.Имя + "Значение"]      = РезультатЗакрытия.Значение;	
	Иначе
		ИмяРеквизитаКомментарий = "Комментарий" + Элемент.Имя;
		Если Форма.Элементы.Найти(ИмяРеквизитаКомментарий) <> Неопределено Тогда
			Форма[ИмяРеквизитаКомментарий] = Комментарий;
		Иначе
			ЭлементФормыПредставление = Форма.Элементы.Найти(Элемент.Имя); // ДекорацияФормы
			Если РезультатЗакрытия.Тип = ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес")
				И РезультатЗакрытия.ВВидеГиперссылки Тогда
				ПараметрыКИ = Форма.ПараметрыКонтактнойИнформации[ДополнительныеПараметры.ИмяЭлементаРазмещения];
				ХранитьИсториюИзменений = ?(ДанныеНаФорме.Свойство("ХранитьИсториюИзменений"), ДанныеНаФорме.ХранитьИсториюИзменений, Ложь);
				КомандыДляВывода = УправлениеКонтактнойИнформациейКлиентСервер.КомандыДляВыводаНаФорму(ПараметрыКИ,
					РезультатЗакрытия.Тип, РезультатЗакрытия.Вид, ХранитьИсториюИзменений);
				ЭлементФормыПредставление.РасширеннаяПодсказка.Заголовок = УправлениеКонтактнойИнформациейКлиентСервер.РасширеннаяПодсказкаАдреса(
					КомандыДляВывода, ДанныеНаФорме.Представление, Комментарий);
			Иначе
				ЭлементФормыПредставление.РасширеннаяПодсказка.Заголовок = Комментарий;
			КонецЕсли;
		КонецЕсли;
		
		Если РезультатЗакрытия.Тип = ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.ВебСтраница") Тогда
			ТекстПредставления = УправлениеКонтактнойИнформациейКлиентСервер.АдресСайта(ТекстПредставления, РезультатЗакрытия.Адрес, Форма.ТолькоПросмотр);
		КонецЕсли;
		
		ДанныеНаФорме.Представление = ТекстПредставления;
		ДанныеНаФорме.Значение      = РезультатЗакрытия.Значение;
		ДанныеНаФорме.Комментарий   = Комментарий;
	КонецЕсли;
	
	Если РезультатЗакрытия.Свойство("ВВидеГиперссылки")
		И РезультатЗакрытия.ВВидеГиперссылки
		И НЕ ЗначениеЗаполнено(ТекстПредставления) Тогда
			ДанныеЗаполнения[Элемент.Имя] = УправлениеКонтактнойИнформациейКлиентСервер.ТекстПустогоАдресаВВидеГиперссылки();
	Иначе
		ДанныеЗаполнения[Элемент.Имя] = ТекстПредставления;
	КонецЕсли;
	
	Если РезультатЗакрытия.Тип = ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес") Тогда
		Результат.Вставить("ОбновитьКонтекстноеМеню", Истина);
	КонецЕсли;
	
	Форма.Модифицированность = Истина;
	ОбновитьКонтактнуюИнформациюФормы(Форма, Результат, ДополнительныеПараметры.АсинхронныйВызов);
КонецПроцедуры

Процедура КонтактнаяИнформацияДобавитьПолеВводаЗавершение(Знач ВыбранныйЭлемент, Знач ДополнительныеПараметры) Экспорт
	Если ВыбранныйЭлемент = Неопределено Тогда
		// Отказ от выбора
		Возврат;
	КонецЕсли;
	
	Если НЕ ЗначениеЗаполнено(ВыбранныйЭлемент.Значение.Ссылка) Тогда
		Форма = ДополнительныеПараметры.Форма;
		ИмяЭлементаДляРазмещения = ДополнительныеПараметры.ИмяЭлементаДляРазмещения;
		ПараметрыКИ = Форма.ПараметрыКонтактнойИнформации[ИмяЭлементаДляРазмещения];
		ПараметрыОткрытияФормы = Новый Структура;
		ПараметрыОткрытияФормы.Вставить("ВладелецКонтактнойИнформации", ПараметрыКИ.Владелец);
		ПараметрыЗакрытияФормы = Новый Структура;
		ПараметрыЗакрытияФормы.Вставить("Форма",  ДополнительныеПараметры.Форма);
		ПараметрыЗакрытияФормы.Вставить("ИмяЭлементаДляРазмещения", ИмяЭлементаДляРазмещения);
		ПараметрыЗакрытияФормы.Вставить("АсинхронныйВызов", ДополнительныеПараметры.АсинхронныйВызов);	
		Оповещение = Новый ОписаниеОповещения("ПослеЗакрытияФормыСпискаВидыКонтактнойИнформации", 
			УправлениеКонтактнойИнформациейКлиент, ПараметрыЗакрытияФормы);
		ОткрытьФорму("Справочник.ВидыКонтактнойИнформации.Форма.ФормаСписка",ПараметрыОткрытияФормы,
			ДополнительныеПараметры.Форма,,,,Оповещение,РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
		Возврат;
	КонецЕсли;
	
	Результат = Новый Структура();
	Результат.Вставить("ДобавляемыйВид", ВыбранныйЭлемент.Значение);
	Результат.Вставить("ИмяЭлементаДляРазмещения", ДополнительныеПараметры.ИмяЭлементаДляРазмещения);
	Результат.Вставить("ИмяКоманды", ДополнительныеПараметры.ИмяКоманды);
	Если ВыбранныйЭлемент.Значение.Тип = ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес") Тогда
		Результат.Вставить("ОбновитьКонтекстноеМеню", Истина);
	КонецЕсли;
	
	Если Не ВыбранныйЭлемент.Значение.РазрешитьВводНесколькихЗначений Тогда
		ДополнительныеПараметры.Форма.ПараметрыКонтактнойИнформации[Результат.ИмяЭлементаДляРазмещения].СписокДобавляемыхЭлементов.Удалить(ВыбранныйЭлемент);
	КонецЕсли;
	
	ОбновитьКонтактнуюИнформациюФормы(ДополнительныеПараметры.Форма, Результат, ДополнительныеПараметры.АсинхронныйВызов);
КонецПроцедуры

Процедура ПослеЗапускаПриложения(ПриложениеЗапущено, Параметры) Экспорт
	
	Если Не ПриложениеЗапущено Тогда 
		СтрокаСПредупреждением = Новый ФорматированнаяСтрока(
			НСтр("ru = 'Для совершения звонка установите программу телефонии, например'"),
			 " ", Новый ФорматированнаяСтрока("Skype",,,, "http://www.skype.com"), ".");
		ПоказатьПредупреждение(Неопределено, СтрокаСПредупреждением);
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Обработчики событий

Процедура ПриНачалеВыбора(Форма, Элемент, Модифицированность, СтандартнаяОбработка, ПараметрыОткрытия, АсинхронныйВызов)
	
	СтандартнаяОбработка = Ложь;
	
	Результат = Новый Структура;
	Результат.Вставить("ИмяРеквизита", Элемент.Имя);
	
	ЭтоТабличнаяЧасть = ЭтоТабличнаяЧасть(Элемент);
	
	Если ЭтоТабличнаяЧасть Тогда
		ДанныеЗаполнения = Форма.Элементы[Форма.ТекущийЭлемент.Имя].ТекущиеДанные;
		Если ДанныеЗаполнения = Неопределено Тогда
			Возврат;
		КонецЕсли;
	Иначе
		ДанныеЗаполнения = Форма;
	КонецЕсли;
	
	ДанныеСтроки = ПолучитьСтрокуДополнительныхЗначений(Форма, Элемент, ЭтоТабличнаяЧасть);
	
	// Если представление было изменено в поле и не соответствует реквизиту, то приводим в соответствие.
	ОбновитьКонтекстноеМеню = Ложь;
	Если Элемент.Вид = ВидПоляФормы.ПолеВвода Тогда
		Если ДанныеЗаполнения[Элемент.Имя] <> Элемент.ТекстРедактирования Тогда
			ДанныеЗаполнения[Элемент.Имя] = Элемент.ТекстРедактирования;
			ПриИзмененииКонтактнойИнформации(Форма, Элемент, ЭтоТабличнаяЧасть, Ложь, АсинхронныйВызов);
			ОбновитьКонтекстноеМеню  = Истина;
			Форма.Модифицированность = Истина;
		КонецЕсли;
		ТекстРедактирования = Элемент.ТекстРедактирования;
	Иначе
		Если ДанныеСтроки <> Неопределено И ЗначениеЗаполнено(ДанныеСтроки.Значение) Тогда
			ТекстРедактирования = Форма[Элемент.Имя];
		Иначе
			ТекстРедактирования = "";
		КонецЕсли;
	КонецЕсли;
	
	ПараметрыКонтактнойИнформации = Форма.ПараметрыКонтактнойИнформации[ДанныеСтроки.ИмяЭлементаДляРазмещения];
	
	ПараметрыОткрытияФормы = Новый Структура;
	ПараметрыОткрытияФормы.Вставить("ВидКонтактнойИнформации", ДанныеСтроки.Вид);
	ПараметрыОткрытияФормы.Вставить("Значение",                ДанныеСтроки.Значение);
	ПараметрыОткрытияФормы.Вставить("Представление",           ТекстРедактирования);
	ПараметрыОткрытияФормы.Вставить("ТолькоПросмотр",          Форма.ТолькоПросмотр Или Элемент.ТолькоПросмотр);
	ПараметрыОткрытияФормы.Вставить("ТипПомещения",            ПараметрыКонтактнойИнформации.ПараметрыАдреса.ТипПомещения);
	ПараметрыОткрытияФормы.Вставить("Страна",                  ПараметрыКонтактнойИнформации.ПараметрыАдреса.Страна);
	ПараметрыОткрытияФормы.Вставить("Индекс",                  ПараметрыКонтактнойИнформации.ПараметрыАдреса.Индекс);
	ПараметрыОткрытияФормы.Вставить("КонтактнаяИнформацияОписаниеДополнительныхРеквизитов", 
		УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(Форма));
	
	Если Не ЭтоТабличнаяЧасть Тогда
		ПараметрыОткрытияФормы.Вставить("Комментарий", ДанныеСтроки.Комментарий);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ПараметрыОткрытия) И ТипЗнч(ПараметрыОткрытия) = Тип("Структура") Тогда
		Для каждого ЗначениеИКлюч Из ПараметрыОткрытия Цикл
			ПараметрыОткрытияФормы.Вставить(ЗначениеИКлюч.Ключ, ЗначениеИКлюч.Значение);
		КонецЦикла;
	КонецЕсли;
	
	ДополнительныеПараметры = ПредставлениеНачалоВыбораЗавершениеДополнительныеПараметры();
	ДополнительныеПараметры.ДанныеЗаполнения = ДанныеЗаполнения;
	ДополнительныеПараметры.ЭтоТабличнаяЧасть = ЭтоТабличнаяЧасть;
	ДополнительныеПараметры.ИмяЭлементаРазмещения = ДанныеСтроки.ИмяЭлементаДляРазмещения;
	ДополнительныеПараметры.ДанныеСтроки = ДанныеСтроки;
	ДополнительныеПараметры.Элемент = Элемент;
	ДополнительныеПараметры.Результат = Результат;
	ДополнительныеПараметры.Форма = Форма;
	ДополнительныеПараметры.ОбновитьКонтекстноеМеню = ОбновитьКонтекстноеМеню;
	ДополнительныеПараметры.АсинхронныйВызов = АсинхронныйВызов;
	
	Оповещение = Новый ОписаниеОповещения("ПредставлениеНачалоВыбораЗавершение", ЭтотОбъект, ДополнительныеПараметры);
	
	ОткрытьФормуКонтактнойИнформации(ПараметрыОткрытияФормы,, Оповещение);
	
КонецПроцедуры

Процедура ПриОчистке(Знач Форма, Знач ИмяРеквизита, АсинхронныйВызов)
	
	Результат = Новый Структура("ИмяРеквизита", ИмяРеквизита);
	НайденныеСтроки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(
		Форма).НайтиСтроки(Результат);
	Если НайденныеСтроки.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	НайденнаяСтрока = НайденныеСтроки[0];
	НайденнаяСтрока.Значение      = "";
	НайденнаяСтрока.Представление = "";
	НайденнаяСтрока.Комментарий   = "";
	
	Форма[ИмяРеквизита] = "";
	Форма.Модифицированность = Истина;
		
	Если НайденнаяСтрока.Тип = ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес") Тогда
		Результат.Вставить("ОбновитьКонтекстноеМеню", Истина);
		Результат.Вставить("ИмяЭлементаДляРазмещения", НайденнаяСтрока.ИмяЭлементаДляРазмещения);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(НайденнаяСтрока.Маска) Тогда
		ЭлементыФормы = Форма.Элементы[ИмяРеквизита]; // ПолеВвода
		Если ЭлементыФормы.Вид = ВидПоляФормы.ПолеВвода Тогда
			ЭлементыФормы.Маска = НайденнаяСтрока.Маска;
		КонецЕсли;
	КонецЕсли;
	
	ОбновитьКонтактнуюИнформациюФормы(Форма, Результат, АсинхронныйВызов);
	
КонецПроцедуры

Процедура ПриВыполненииКоманды(Знач Форма, Знач ИмяКоманды, АсинхронныйВызов)

	Если СтрНачинаетсяС(ИмяКоманды, "КонтактнаяИнформацияДобавитьПолеВвода") Тогда

		ДополнительныеПараметры = Новый Структура;

		ИмяЭлементаДляРазмещения = Сред(ИмяКоманды, СтрДлина("КонтактнаяИнформацияДобавитьПолеВвода") + 1);
		ДополнительныеПараметры.Вставить("АсинхронныйВызов", АсинхронныйВызов);
		ДополнительныеПараметры.Вставить("Форма", Форма);
		ДополнительныеПараметры.Вставить("ИмяЭлементаДляРазмещения", ИмяЭлементаДляРазмещения);
		ДополнительныеПараметры.Вставить("ИмяКоманды", ИмяКоманды);
		Оповещение = Новый ОписаниеОповещения("КонтактнаяИнформацияДобавитьПолеВводаЗавершение", ЭтотОбъект,
			ДополнительныеПараметры);
		Форма.ПоказатьВыборИзМеню(Оповещение,
			Форма.ПараметрыКонтактнойИнформации[ИмяЭлементаДляРазмещения].СписокДобавляемыхЭлементов,
			Форма.Элементы[ИмяКоманды]);

		Возврат;

	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, "Команда") Тогда

		ИмяРеквизита = УдалитьПрефиксСтроки(ИмяКоманды, "Команда");
		КомандаКонтекстногоМеню = Неопределено;
		
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, "МенюПодменюАдрес") Тогда
		
		ИмяРеквизита         = УдалитьПрефиксСтроки(ИмяКоманды, "МенюПодменюАдрес");
		Позиция              = СтрНайти(ИмяРеквизита, "_КонтактнаяИнформацияПоле");
		ИмяРеквизитаИсточник = Лев(ИмяРеквизита, Позиция -1);
		ИмяРеквизита         = Сред(ИмяРеквизита, Позиция + 1);
		КомандаКонтекстногоМеню = Неопределено;
		
	Иначе

		КомандаКонтекстногоМеню = КомандаКонтекстногоМеню(ИмяКоманды);
		ИмяРеквизита = КомандаКонтекстногоМеню.ИмяРеквизита;

	КонецЕсли;

	Результат = Новый Структура("ИмяРеквизита", ИмяРеквизита);
	НайденныеСтроки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(
		Форма).НайтиСтроки(Результат);
	Если НайденныеСтроки.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;

	НайденнаяСтрока          = НайденныеСтроки[0];
	ТипКонтактнойИнформации  = НайденнаяСтрока.Тип;
	ИмяЭлементаДляРазмещения = НайденнаяСтрока.ИмяЭлементаДляРазмещения;
	Результат.Вставить("ИмяЭлементаДляРазмещения", ИмяЭлементаДляРазмещения);
	Результат.Вставить("ТипКонтактнойИнформации", НайденнаяСтрока.Тип);
	
	Если КомандаКонтекстногоМеню <> Неопределено Тогда	
		ПервыйЭлемент = НайденнаяСтрока.ИмяРеквизита;
		ОписаниеКонтактнойИнформацииНаФорме = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(
				Форма);
		Индекс = ОписаниеКонтактнойИнформацииНаФорме.Индекс(НайденнаяСтрока);
		Если КомандаКонтекстногоМеню.НаправлениеПеремещения = 1 Тогда
			Если Индекс < ОписаниеКонтактнойИнформацииНаФорме.Количество() - 1 Тогда
				ВторойЭлемент = ОписаниеКонтактнойИнформацииНаФорме.Получить(Индекс + 1).ИмяРеквизита;
			КонецЕсли;
		Иначе
			Если Индекс > 0 Тогда
				ВторойЭлемент = ОписаниеКонтактнойИнформацииНаФорме.Получить(Индекс - 1).ИмяРеквизита;
			КонецЕсли;
		КонецЕсли;
		Результат = Новый Структура;
		Результат.Вставить("ПоменятьМестамиЭлементы", Истина); 
		Результат.Вставить("ПервыйЭлемент", ПервыйЭлемент); 
		Результат.Вставить("ВторойЭлемент", ВторойЭлемент); 
		Результат.Вставить("ИмяЭлементаДляРазмещения", ИмяЭлементаДляРазмещения); 	
		Форма.ТекущийЭлемент = Форма.Элементы[ВторойЭлемент];
		ОбновитьКонтактнуюИнформациюФормы(Форма, Результат, АсинхронныйВызов);
		
	ИначеЕсли СтрНачинаетсяС(ИмяКоманды, "МенюПодменюАдрес") И ТипКонтактнойИнформации = ПредопределенноеЗначение(
		"Перечисление.ТипыКонтактнойИнформации.Адрес") Тогда

		Результат = Новый Структура("ИмяРеквизита", ИмяРеквизитаИсточник);	
		НайденныеСтроки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(
			Форма).НайтиСтроки(Результат);
		Если НайденныеСтроки.Количество() = 0 Тогда
			Возврат;
		КонецЕсли;
	
		СтрокаПотребитель = НайденныеСтроки[0];
		Комментарий = СтрокаПотребитель.Комментарий; // Сохраняем старый комментарий.
		Если СтрокаПотребитель.Свойство("МеждународныйФорматАдреса") И СтрокаПотребитель.МеждународныйФорматАдреса Тогда

			ЗаполнитьЗначенияСвойств(СтрокаПотребитель, НайденнаяСтрока, "Комментарий");
			ПредставлениеАдреса = СтроковыеФункцииКлиент.СтрокаЛатиницей(НайденнаяСтрока.Представление);
			СтрокаПотребитель.Представление        = ПредставлениеАдреса;
			Форма[СтрокаПотребитель.ИмяРеквизита]  = ПредставлениеАдреса;
			СтрокаПотребитель.Значение = УправлениеКонтактнойИнформациейСлужебныйВызовСервера.КонтактнаяИнформацияПоПредставлению(
				ПредставлениеАдреса, ТипКонтактнойИнформации);

		Иначе

			ЗаполнитьЗначенияСвойств(СтрокаПотребитель, НайденнаяСтрока, "Значение, Представление,Комментарий");
			Форма[СтрокаПотребитель.ИмяРеквизита] = НайденнаяСтрока.Представление;

		КонецЕсли;

		Форма.Модифицированность = Истина;
		Результат = Новый Структура;
		Результат.Вставить("ОбновитьКонтекстноеМеню", Истина);
		Результат.Вставить("ИмяРеквизита", СтрокаПотребитель.ИмяРеквизита);
		Результат.Вставить("Комментарий", Комментарий);
		Результат.Вставить("ИмяЭлементаДляРазмещения", НайденнаяСтрока.ИмяЭлементаДляРазмещения);
		ОбновитьКонтактнуюИнформациюФормы(Форма, Результат, АсинхронныйВызов);
		
	Иначе
		ПараметрыКИ = Форма.ПараметрыКонтактнойИнформации[ИмяЭлементаДляРазмещения];
		ВладелецКИ = ПараметрыКИ.Владелец;
	
		КомандыДляВывода = УправлениеКонтактнойИнформациейКлиентСервер.КомандыДляВыводаНаФорму(ПараметрыКИ,
			ТипКонтактнойИнформации, НайденнаяСтрока.Вид, НайденнаяСтрока.ХранитьИсториюИзменений);

		КоличествоКоманд = КомандыДляВывода.Количество();

		Если КоличествоКоманд = 0 Тогда
			Возврат;
		КонецЕсли;

		КонтактнаяИнформация = ПараметрКонтактнаяИнформацияДляВыполненияКоманд(НайденнаяСтрока.Представление, 
			НайденнаяСтрока.Значение, НайденнаяСтрока.Тип, НайденнаяСтрока.Вид);
		ДополнительныеПараметры = ДополнительныеПараметрыДляВыполненияКоманд(ВладелецКИ, Форма, НайденнаяСтрока.ИмяРеквизита, АсинхронныйВызов);
		Параметры = Новый Структура("КонтактнаяИнформация, ДополнительныеПараметры", КонтактнаяИнформация, ДополнительныеПараметры);

		Если КоличествоКоманд = 1 Тогда

			Для Каждого Команда Из КомандыДляВывода Цикл
				ВыполнитьКомандуКонтактнойИнформации(Команда.Значение.Действие, Параметры);
			КонецЦикла;

		ИначеЕсли КоличествоКоманд > 1 Тогда
			Список = Новый СписокЗначений;
			Для Каждого Команда Из КомандыДляВывода Цикл
				Список.Добавить(Команда.Значение.Действие, Команда.Значение.Заголовок, , Команда.Значение.Картинка);
			КонецЦикла;

			ОповещениеМеню = Новый ОписаниеОповещения("ПослеВыбораИзМеню", ЭтотОбъект, Параметры);
			Форма.ПоказатьВыборИзМеню(ОповещениеМеню, Список, Форма.Элементы[ИмяКоманды]);
		КонецЕсли;
	КонецЕсли;

КонецПроцедуры

Процедура ПриОбработкеНавигационнойСсылки(Форма, Элемент, НавигационнаяСсылкаФорматированнойСтроки, СтандартнаяОбработка, АсинхронныйВызов)
	
	СтандартнаяОбработка = Ложь;
	
	Если СтрЗаканчиваетсяНа(Элемент.Имя, "РасширеннаяПодсказка") Тогда
		ИмяКоманды = НавигационнаяСсылкаФорматированнойСтроки;
		ИмяРеквизита = УдалитьПостфиксСтроки(Элемент.Имя, "РасширеннаяПодсказка");
		ПередВыполнениемКомандыИзРасширеннойПодсказкиАдреса(Форма, Элемент, ИмяРеквизита, ИмяКоманды, АсинхронныйВызов);
		Возврат;
	КонецЕсли;
	
	АдресСсылки = Форма[Элемент.Имя];
	Если НавигационнаяСсылкаФорматированнойСтроки = УправлениеКонтактнойИнформациейКлиентСервер.НавигационнаяСсылкаВебСайта() 
		Или СокрЛП(Строка(АдресСсылки)) = УправлениеКонтактнойИнформациейКлиентСервер.ТекстПустогоАдресаВВидеГиперссылки() Тогда
		
		СтандартнаяОбработкаВыбора = Истина;
		
		Если АсинхронныйВызов Тогда
			НачатьВыбор(Форма, Элемент, Истина, СтандартнаяОбработкаВыбора);
		Иначе
			НачалоВыбора(Форма, Элемент, истина, СтандартнаяОбработкаВыбора);
		КонецЕсли;
		
	Иначе
		ПерейтиПоВебСсылке("", НавигационнаяСсылкаФорматированнойСтроки);
	КонецЕсли;
	
КонецПроцедуры

// Прочие

// Ввод комментария из контекстного меню.
Процедура ВвестиКомментарий(Знач Форма, Знач ИмяРеквизита, Знач НайденнаяСтрока, Знач Результат, АсинхронныйВызов)
	Комментарий = НайденнаяСтрока.Комментарий;
	
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("Форма", Форма);
	ДополнительныеПараметры.Вставить("ИмяРеквизитаКомментария", "Комментарий" + ИмяРеквизита);
	ДополнительныеПараметры.Вставить("НайденнаяСтрока", НайденнаяСтрока);
	ДополнительныеПараметры.Вставить("ПредыдущийКомментарий", Комментарий);
	ДополнительныеПараметры.Вставить("Результат", Результат);
	ДополнительныеПараметры.Вставить("ИмяЭлементаДляРазмещения", НайденнаяСтрока.ИмяЭлементаДляРазмещения);
	ДополнительныеПараметры.Вставить("АсинхронныйВызов", АсинхронныйВызов);
	
	Оповещение = Новый ОписаниеОповещения("ВвестиКомментарийЗавершение", ЭтотОбъект, ДополнительныеПараметры);
	
	ОбщегоНазначенияКлиент.ПоказатьФормуРедактированияМногострочногоТекста(Оповещение, Комментарий,
		НСтр("ru = 'Комментарий'"));
КонецПроцедуры

// Завершение немодального диалога.
Процедура ВвестиКомментарийЗавершение(Знач Комментарий, Знач ДополнительныеПараметры) Экспорт
	Если Комментарий = Неопределено Или Комментарий = ДополнительныеПараметры.ПредыдущийКомментарий Тогда
		// Отказ от ввода или нет изменений.
		Возврат;
	КонецЕсли;
	
	КомментарийБылПустой  = ПустаяСтрока(ДополнительныеПараметры.ПредыдущийКомментарий);
	КомментарийСталПустой = ПустаяСтрока(Комментарий);
	
	ДополнительныеПараметры.НайденнаяСтрока.Комментарий = Комментарий;
	
	Если КомментарийБылПустой И Не КомментарийСталПустой Тогда
		ДополнительныеПараметры.Результат.Вставить("ЭтоДобавлениеКомментария", Истина);
	ИначеЕсли Не КомментарийБылПустой И КомментарийСталПустой Тогда
		ДополнительныеПараметры.Результат.Вставить("ЭтоДобавлениеКомментария", Ложь);
	Иначе
		Если ДополнительныеПараметры.Форма.Элементы.Найти(ДополнительныеПараметры.ИмяРеквизитаКомментария) <> Неопределено Тогда
			Элемент = ДополнительныеПараметры.Форма.Элементы[ДополнительныеПараметры.ИмяРеквизитаКомментария]; // ДополнениеЭлементаФормы
			Элемент.Заголовок = Комментарий;
		Иначе
			ДополнительныеПараметры.Результат.Вставить("ЭтоДобавлениеКомментария", Истина);
		КонецЕсли;
	КонецЕсли;
	
	ДополнительныеПараметры.Форма.Модифицированность = Истина;
	ОбновитьКонтактнуюИнформациюФормы(ДополнительныеПараметры.Форма, ДополнительныеПараметры.Результат, ДополнительныеПараметры.АсинхронныйВызов)
	
КонецПроцедуры

Процедура ПриИзмененииКонтактнойИнформации(Форма, Элемент, ЭтоТабличнаяЧасть, ОбновитьФорму, АсинхронныйВызов)
	
	Префикс = "Комментарий";
	Если СтрНачинаетсяС(Элемент.Имя, Префикс) Тогда
		ИмяРеквизита = УдалитьПрефиксСтроки(Элемент.Имя, Префикс);
		Результат = Новый Структура;
		Результат.Вставить("ИмяРеквизита", ИмяРеквизита);
		НайденныеСтроки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(Форма).НайтиСтроки(Результат);
		Если НайденныеСтроки.Количество() = 0 Тогда
			Возврат;
		КонецЕсли;
		НайденнаяСтрока             = НайденныеСтроки[0];
		ИмяЭлементаДляРазмещения    = НайденнаяСтрока.ИмяЭлементаДляРазмещения;
		НайденнаяСтрока.Комментарий = Элемент.ТекстРедактирования;
		Результат.Вставить("ИмяЭлементаДляРазмещения", ИмяЭлементаДляРазмещения);
		Результат.Вставить("ТипКонтактнойИнформации", НайденнаяСтрока.Тип);
		Результат.Вставить("ЭтоДобавлениеКомментария", Истина);
		ОбновитьКонтактнуюИнформациюФормы(Форма, Результат, АсинхронныйВызов);
		Возврат;
	КонецЕсли;
	
	ЭтоТабличнаяЧасть = ЭтоТабличнаяЧасть(Элемент);
	
	Если ЭтоТабличнаяЧасть Тогда
		ДанныеЗаполнения = Форма.Элементы[Форма.ТекущийЭлемент.Имя].ТекущиеДанные;
		Если ДанныеЗаполнения = Неопределено Тогда
			Возврат;
		КонецЕсли;
	Иначе
		ДанныеЗаполнения = Форма;
	КонецЕсли;
	
	// Если это очистка, то сбрасываем представление.
	ДанныеСтроки = ПолучитьСтрокуДополнительныхЗначений(Форма, Элемент, ЭтоТабличнаяЧасть);
	Если ДанныеСтроки = Неопределено Тогда 
		Возврат;
	КонецЕсли;
	
	Текст = Элемент.ТекстРедактирования;
	Если ПустаяСтрока(Текст) Тогда
		
		ДанныеЗаполнения[Элемент.Имя] = "";
		Если ЭтоТабличнаяЧасть Тогда
			ДанныеЗаполнения[Элемент.Имя + "Значение"] = "";
		КонецЕсли;
		ДанныеСтроки.Представление = "";
		ДанныеСтроки.Значение      = "";
		Результат = Новый Структура("ОбновитьКонтекстноеМеню, ИмяЭлементаДляРазмещения", Истина, ДанныеСтроки.ИмяЭлементаДляРазмещения);
		Если ОбновитьФорму Тогда
			ОбновитьКонтекстноеМеню(Форма, ДанныеСтроки.ИмяЭлементаДляРазмещения);
		КонецЕсли;      
		Если ЗначениеЗаполнено(ДанныеСтроки.Маска) И Элемент.Вид = ВидПоляФормы.ПолеВвода Тогда
			Элемент.Маска = ДанныеСтроки.Маска;  
		КонецЕсли;	
		Возврат;
		
	КонецЕсли;
	
	Если ДанныеСтроки.Свойство("ХранитьИсториюИзменений")
		И ДанныеСтроки.ХранитьИсториюИзменений
		И НачалоДня(ДанныеСтроки.ДействуетС) <> НачалоДня(ОбщегоНазначенияКлиент.ДатаСеанса()) Тогда
		КонтактнаяИнформацияОписаниеДополнительныхРеквизитов = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(Форма);
		ИсторическаяКонтактнаяИнформация = КонтактнаяИнформацияОписаниеДополнительныхРеквизитов.Добавить();
		ЗаполнитьЗначенияСвойств(ИсторическаяКонтактнаяИнформация, ДанныеСтроки);
		ИсторическаяКонтактнаяИнформация.ЭтоИсторическаяКонтактнаяИнформация = Истина;
		ИсторическаяКонтактнаяИнформация.ИмяРеквизита = "";
		ДанныеСтроки.ДействуетС = НачалоДня(ОбщегоНазначенияКлиент.ДатаСеанса());
	КонецЕсли;
	
	ДанныеСтроки.Значение = УправлениеКонтактнойИнформациейСлужебныйВызовСервера.КонтактнаяИнформацияПоПредставлению(Текст, ДанныеСтроки.Вид);
	ДанныеСтроки.Представление = Текст;
	
	Если ЭтоТабличнаяЧасть Тогда
		ДанныеЗаполнения[Элемент.Имя + "Значение"]      = ДанныеСтроки.Значение;
	КонецЕсли;
	
	Если ДанныеСтроки.Тип = ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес") И ОбновитьФорму Тогда
		Результат = Новый Структура("ОбновитьКонтекстноеМеню, ИмяЭлементаДляРазмещения", Истина, ДанныеСтроки.ИмяЭлементаДляРазмещения);
		ОбновитьКонтактнуюИнформациюФормы(Форма, Результат, АсинхронныйВызов)
	КонецЕсли;

КонецПроцедуры

// Контекстный вызов
Процедура ОбновитьКонтактнуюИнформациюФормы(Форма, Результат, АсинхронныйВызов)
	
	Если АсинхронныйВызов Тогда
		Оповещение = Новый ОписаниеОповещения("Подключаемый_ПродолжитьОбновлениеКонтактнойИнформации", Форма);
		ВыполнитьОбработкуОповещения(Оповещение, Результат);
	Иначе
		Форма.Подключаемый_ОбновитьКонтактнуюИнформацию(Результат);
	КонецЕсли;
	
КонецПроцедуры

// Возвращает строку дополнительных значений по имени реквизита.
//
// Параметры:
//    Форма   - ФормаКлиентскогоПриложения - передаваемая форма.
//    Элемент - ДанныеФормыСтруктураСКоллекцией - данные формы.
//
// Возвращаемое значение:
//    см. УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме
//    Неопределено    - при отсутствии данных.
//
Функция ПолучитьСтрокуДополнительныхЗначений(Форма, Элемент, ЭтоТабличнаяЧасть = Ложь)
	
	Отбор = Новый Структура("ИмяРеквизита", Элемент.Имя);
	Строки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(Форма).НайтиСтроки(Отбор);
	ДанныеСтроки = ?(Строки.Количество() = 0, Неопределено, Строки[0]);
	
	Если ЭтоТабличнаяЧасть И ДанныеСтроки <> Неопределено Тогда
		
		ПутьКСтроке = Форма.Элементы[Форма.ТекущийЭлемент.Имя].ТекущиеДанные;
		
		ДанныеСтроки.Представление = ПутьКСтроке[Элемент.Имя];
		ДанныеСтроки.Значение      = ПутьКСтроке[Элемент.Имя + "Значение"];
		
	КонецЕсли;
	
	Возврат ДанныеСтроки;
	
КонецФункции

Функция ЭтоТабличнаяЧасть(Элемент)
	
	Родитель = Элемент.Родитель;
	
	Пока ТипЗнч(Родитель) <> Тип("ФормаКлиентскогоПриложения") Цикл
		
		Если ТипЗнч(Родитель) = Тип("ТаблицаФормы") Тогда
			Возврат Истина;
		КонецЕсли;
		
		Родитель = Родитель.Родитель;
		
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

// определение команды контекстного меню.
Функция КомандаКонтекстногоМеню(ИмяКоманды)
	
	Результат = Новый Структура("Команда, НаправлениеПеремещения, ИмяРеквизита", Неопределено, 0, Неопределено);
	
	ИмяРеквизита = ?(СтрНачинаетсяС(ИмяКоманды, "КонтекстноеМенюПодменю"),
		СтрЗаменить(ИмяКоманды, "КонтекстноеМенюПодменю", ""), СтрЗаменить(ИмяКоманды, "КонтекстноеМеню", ""));
		
	Если СтрНачинаетсяС(ИмяРеквизита, "Вверх") Тогда
		Результат.ИмяРеквизита = СтрЗаменить(ИмяРеквизита, "Вверх", "");
		Результат.НаправлениеПеремещения = -1;
		Результат.Команда = "Вверх";
	ИначеЕсли СтрНачинаетсяС(ИмяРеквизита, "Вниз") Тогда
		Результат.ИмяРеквизита = СтрЗаменить(ИмяРеквизита, "Вниз", "");
		Результат.НаправлениеПеремещения = 1;
		Результат.Команда = "Вниз";
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Проверяет, установлена ли программа телефонии на компьютер.
//  Проверка возможна только в тонком клиенте для Windows.
//
// Параметры:
//  ИмяПротокола - Строка - имя проверяемого URI протокола, возможные варианты "skype", "tel", "sip".
//                          Если параметр не указан, то проверяются все протоколы. 
// 
// Возвращаемое значение:
//  Строка - имя доступного URI протокола зарегистрирована в реестре. Пустая строка - если протокол не доступен.
//    Неопределенно если проверка не возможна.
//
Функция ПрограммаТелефонииУстановлена(ИмяПротокола = Неопределено)
	
	Если ОбщегоНазначенияКлиент.ЭтоWindowsКлиент() Тогда
		Если ЗначениеЗаполнено(ИмяПротокола) Тогда
			Возврат ?(ИмяПротоколаЗарегистрированоВРеестре(ИмяПротокола), ИмяПротокола, "");
		Иначе
			СписокПротоколов = Новый Массив;
			СписокПротоколов.Добавить("tel");
			СписокПротоколов.Добавить("sip");
			СписокПротоколов.Добавить("skype");
			Для каждого ИмяПротокола Из СписокПротоколов Цикл
				Если ИмяПротоколаЗарегистрированоВРеестре(ИмяПротокола) Тогда
					Возврат ИмяПротокола;
				КонецЕсли;
			КонецЦикла;
			Возврат Неопределено;
		КонецЕсли;
	КонецЕсли;
	
	// Считаем что для Linux и MacOS всегда есть программа.
	// если будет ошибка - она будет обработана в момент запуска.
	Возврат ИмяПротокола;
КонецФункции

Функция ИмяПротоколаЗарегистрированоВРеестре(ИмяПротокола)
	
#Если МобильныйКлиент Тогда
	Возврат Ложь;
#Иначе
	Попытка
		Оболочка = Новый COMОбъект("Wscript.Shell");
		Оболочка.RegRead("HKEY_CLASSES_ROOT\" + ИмяПротокола + "\");
	Исключение
		Возврат Ложь;
	КонецПопытки;
	Возврат Истина;
#КонецЕсли

КонецФункции

Процедура ПослеВыбораИзМеню(ВыбранныйЭлемент, Параметры) Экспорт
	
	Если ВыбранныйЭлемент <> Неопределено Тогда
		ВыполнитьКомандуКонтактнойИнформации(ВыбранныйЭлемент.Значение, Параметры);
	КонецЕсли;
	
КонецПроцедуры

Процедура ОткрытьSkype(СтрокаЗапуска)
	
	#Если НЕ ВебКлиент Тогда
		Если ПустаяСтрока(ПрограммаТелефонииУстановлена("skype")) Тогда
			ПоказатьПредупреждение(Неопределено, НСтр("ru = 'Для совершения звонка по Skype установите программу.'"));
			Возврат;
		КонецЕсли;
	#КонецЕсли
	
	Оповещение = Новый ОписаниеОповещения("ПослеЗапускаПриложения", ЭтотОбъект);
	ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку(СтрокаЗапуска, Оповещение);
	
КонецПроцедуры

// Конструктор дополнительных параметров для формы истории
// 
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//   ПараметрыКонтактнойИнформации - Структура
//   АсинхронныйВызов - Булево
// Возвращаемое значение:
//   Структура:
//   * Форма - ФормаКлиентскогоПриложения
//   * АсинхронныйВызов - Булево
//   * ИмяЭлементаДляРазмещения - Строка
//   * Вид - СправочникСсылка.ВидыКонтактнойИнформации
//   * ИмяЭлемента - Строка
//
Функция ПослеЗакрытияФормыИсторииДополнительныеПараметры(Знач Форма, ПараметрыКонтактнойИнформации, Знач АсинхронныйВызов)
	
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("Форма", Форма);
	ДополнительныеПараметры.Вставить("ИмяЭлемента", ПараметрыКонтактнойИнформации.ИмяРеквизита);
	ДополнительныеПараметры.Вставить("Вид", ПараметрыКонтактнойИнформации.Вид);
	ДополнительныеПараметры.Вставить("ИмяЭлементаДляРазмещения", ПараметрыКонтактнойИнформации.ИмяЭлементаДляРазмещения);
	ДополнительныеПараметры.Вставить("АсинхронныйВызов", АсинхронныйВызов);

	
	Возврат ДополнительныеПараметры;
	
КонецФункции

// Возвращаемое значение:
//   Структура:
//   * АсинхронныйВызов - Булево
//   * ОбновитьКонтекстноеМеню - Булево
//   * Форма - Неопределено
//   * Результат - Неопределено
//   * Элемент - ДекорацияФормы
//             - ГруппаФормы
//             - КнопкаФормы
//             - ТаблицаФормы
//             - ПолеФормы
//   * ДанныеСтроки - Неопределено
//                  - ДанныеФормыЭлементКоллекции из см. УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме
//   * ИмяЭлементаРазмещения - Строка
//   * ЭтоТабличнаяЧасть - Булево
//   * ДанныеЗаполнения - Строка
//
Функция ПредставлениеНачалоВыбораЗавершениеДополнительныеПараметры()

	ДополнительныеПараметры = Новый Структура;
	
	ДополнительныеПараметры.Вставить("ДанныеЗаполнения",        "");
	ДополнительныеПараметры.Вставить("ЭтоТабличнаяЧасть",       Ложь);
	ДополнительныеПараметры.Вставить("ИмяЭлементаРазмещения",   "");
	ДополнительныеПараметры.Вставить("ДанныеСтроки",            Неопределено);
	ДополнительныеПараметры.Вставить("Элемент",                 Неопределено);
	ДополнительныеПараметры.Вставить("Результат",               Неопределено);
	ДополнительныеПараметры.Вставить("Форма",                   Неопределено);
	ДополнительныеПараметры.Вставить("ОбновитьКонтекстноеМеню", Ложь);
	ДополнительныеПараметры.Вставить("АсинхронныйВызов",        Ложь);
	
	Возврат ДополнительныеПараметры;
		
КонецФункции 

////////////////////////////////////////////////////////////////////////////////
// Возвращает строку, в которой все не алфавитно-числовые символы (кроме -_.)
// заменены на знак процентов (%) с последующими двумя шестнадцатеричными цифрами и
// пробелами, кодированными как знаки плюс (+).Она кодируется тем же способом, что и
// post данные WWW-формы, то есть как в типе носителя application/x-www-form-urlencoded.

Функция ДекодированиеСтроки(Строка)
	Результат = "";
	Для НомерСимвола = 1 По СтрДлина(Строка) Цикл
		КодСимвола = КодСимвола(Строка, НомерСимвола);
		Символ = Сред(Строка, НомерСимвола, 1);
		
		// пропускаем A..Z, a..z, 0..9
		Если СтрНайти("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", Символ) > 0 Тогда // символы -_.!~*\() кодируем как небезопасные  
			Результат = Результат + Символ;
			Продолжить;
		КонецЕсли;
		
		Если Символ = " " Тогда
			Результат = Результат + "+";
			Продолжить;
		КонецЕсли;
		
		Если КодСимвола <= 127 Тогда // 0x007F
			Результат = Результат + ПредставлениеБайта(КодСимвола);
		ИначеЕсли КодСимвола <= 2047 Тогда // 0x07FF 
			Результат = Результат 
					  + ПредставлениеБайта(
					  					   БинарныйМассивВЧисло(
																ЛогическоеПобитовоеИли(
																			 ЧислоВБинарныйМассив(192,8),
																			 ЧислоВБинарныйМассив(Цел(КодСимвола / Pow(2,6)),8)))); // 0xc0 | (ch >> 6)
			Результат = Результат 
					  + ПредставлениеБайта(
					  					   БинарныйМассивВЧисло(
										   						ЛогическоеПобитовоеИли(
																			 ЧислоВБинарныйМассив(128,8),
																			 ЛогическоеПобитовоеИ(
																			 			ЧислоВБинарныйМассив(КодСимвола,8),
																						ЧислоВБинарныйМассив(63,8)))));  //0x80 | (ch & 0x3F)
		Иначе  // 0x7FF < ch <= 0xFFFF
			Результат = Результат 
					  + ПредставлениеБайта	(
					  						 БинарныйМассивВЧисло(
																  ЛогическоеПобитовоеИли(
																			   ЧислоВБинарныйМассив(224,8), 
																			   ЧислоВБинарныйМассив(Цел(КодСимвола / Pow(2,12)),8)))); // 0xe0 | (ch >> 12)
											
			Результат = Результат 
					  + ПредставлениеБайта(
					  					   БинарныйМассивВЧисло(
										   						ЛогическоеПобитовоеИли(
																			 ЧислоВБинарныйМассив(128,8),
																			 ЛогическоеПобитовоеИ(
																			 			ЧислоВБинарныйМассив(Цел(КодСимвола / Pow(2,6)),8),
																						ЧислоВБинарныйМассив(63,8)))));  //0x80 | ((ch >> 6) & 0x3F)
											
			Результат = Результат 
					  + ПредставлениеБайта(
					  					   БинарныйМассивВЧисло(
										   						ЛогическоеПобитовоеИли(
																			 ЧислоВБинарныйМассив(128,8),
																			 ЛогическоеПобитовоеИ(
																			 			ЧислоВБинарныйМассив(КодСимвола,8),
																						ЧислоВБинарныйМассив(63,8)))));  //0x80 | (ch & 0x3F)
								
		КонецЕсли;
	КонецЦикла;
	Возврат Результат;
КонецФункции

Функция ПредставлениеБайта(Знач Байт)
	Результат = "";
	СтрокаСимволов = "0123456789ABCDEF";
	Для Счетчик = 1 По 2 Цикл
		Результат = Сред(СтрокаСимволов, Байт % 16 + 1, 1) + Результат;
		Байт = Цел(Байт / 16);
	КонецЦикла;
	Возврат "%" + Результат;
КонецФункции

Функция ЧислоВБинарныйМассив(Знач Число, Знач ВсегоРазрядов = 32)
	Результат = Новый Массив;
	ТекущийРазряд = 0;
	Пока ТекущийРазряд < ВсегоРазрядов Цикл
		ТекущийРазряд = ТекущийРазряд + 1;
		Результат.Добавить(Булево(Число % 2));
		Число = Цел(Число / 2);
	КонецЦикла;
	Возврат Результат;
КонецФункции

Функция БинарныйМассивВЧисло(Массив)
	Результат = 0;
	Для НомерРазряда = -(Массив.Количество()-1) По 0 Цикл
		Результат = Результат * 2 + Число(Массив[-НомерРазряда]);
	КонецЦикла;
	Возврат Результат;
КонецФункции

Функция ЛогическоеПобитовоеИ(БинарныйМассив1, БинарныйМассив2)
	Результат = Новый Массив;
	Для Индекс = 0 По БинарныйМассив1.Количество()-1 Цикл
		Результат.Добавить(БинарныйМассив1[Индекс] И БинарныйМассив2[Индекс]);
	КонецЦикла;
	Возврат Результат;
КонецФункции

Функция ЛогическоеПобитовоеИли(БинарныйМассив1, БинарныйМассив2)
	Результат = Новый Массив;
	Для Индекс = 0 По БинарныйМассив1.Количество()-1 Цикл
		Результат.Добавить(БинарныйМассив1[Индекс] Или БинарныйМассив2[Индекс]);
	КонецЦикла;
	Возврат Результат;
КонецФункции

Процедура ОбновитьКонтекстноеМеню(Форма, ИмяЭлементаДляРазмещения)
	
	ПараметрыКонтактнойИнформации = Форма.ПараметрыКонтактнойИнформации[ИмяЭлементаДляРазмещения]; // ДанныеФормаКоллекция
	ВсеСтроки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(Форма);
	НайденныеСтроки = ВсеСтроки.НайтиСтроки( 
		Новый Структура("Тип, ЭтоРеквизитТабличнойЧасти", ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес"), Ложь));
		
	ОбщееКоличествоКоманд = 0;
	Для Каждого СтрокаКИ Из ВсеСтроки Цикл
		
		Если ОбщееКоличествоКоманд > 50 Тогда // Ограничение для большого количества адресов на форме
			Прервать;
		КонецЕсли;
		
		Если СтрокаКИ.Тип <> ПредопределенноеЗначение("Перечисление.ТипыКонтактнойИнформации.Адрес") Тогда
			Продолжить;
		КонецЕсли;
		
		КонтекстноеПодменюКопироватьАдреса = Форма.Элементы.Найти("КонтекстноеПодменюКопироватьАдреса" + СтрокаКИ.ИмяРеквизита);
		Если КонтекстноеПодменюКопироватьАдреса = Неопределено Тогда
			Продолжить;
		КонецЕсли;
			
		КоличествоКомандВПодменю = 0;
		СписокАдресовВПодменю = Новый Соответствие();
		ДанныеАдреса = Новый Структура("Представление, Адрес", СтрокаКИ.Представление, СтрокаКИ.Значение);
		СписокАдресовВПодменю.Вставить(ВРег(СтрокаКИ.Представление), ДанныеАдреса);
		
		Для Каждого Адрес Из НайденныеСтроки Цикл
			
			Если КоличествоКомандВПодменю > 7 Тогда // Ограничение для большого количества адресов на форме
				Прервать;
			КонецЕсли;
			
			Если Адрес.ЭтоИсторическаяКонтактнаяИнформация Или Адрес.ИмяРеквизита = СтрокаКИ.ИмяРеквизита Тогда
				Продолжить;
			КонецЕсли;
			
			Если НЕ ЗначениеЗаполнено(Адрес.Представление) Тогда
				Продолжить;
			КонецЕсли;
			
			ИмяКоманды = "МенюПодменюАдрес" + СтрокаКИ.ИмяРеквизита + "_" + Адрес.ИмяРеквизита;
			Команда = Форма.Команды.Найти(ИмяКоманды);
			Если Команда = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			ПредставлениеАдреса = ?(СтрокаКИ.МеждународныйФорматАдреса,
				СтроковыеФункцииКлиент.СтрокаЛатиницей(Адрес.Представление), Адрес.Представление);
			
			Если СписокАдресовВПодменю[ВРег(Адрес.Представление)] <> Неопределено Тогда
				ПредставлениеАдреса = "";
			Иначе
				ДанныеАдреса = Новый Структура("Представление, Адрес", ПредставлениеАдреса, Адрес.Значение);
				Если СтрокаКИ.МеждународныйФорматАдреса Тогда
					ДанныеАдреса.Адрес = УправлениеКонтактнойИнформациейСлужебныйВызовСервера.КонтактнаяИнформацияПоПредставлению(
						ПредставлениеАдреса, Адрес.Тип);
				КонецЕсли;
				СписокАдресовВПодменю.Вставить(ВРег(Адрес.Представление), ДанныеАдреса);
			КонецЕсли;
				
			ДобавитьКнопкуСкопироватьАдрес(Форма, ИмяКоманды, ПредставлениеАдреса, ПараметрыКонтактнойИнформации, 
				КонтекстноеПодменюКопироватьАдреса);
			
		КонецЦикла;
		
		Поле = Форма.Элементы[СтрокаКИ.ИмяРеквизита];
		Если Поле.Вид = ВидПоляФормы.ПолеВвода Тогда
			Поле.СписокВыбора.Очистить();
			ПредставлениеДляПоиска = ВРег(СтрокаКИ.Представление);
			Для Каждого ДанныеАдреса Из СписокАдресовВПодменю Цикл
				Если ДанныеАдреса.Ключ <> ПредставлениеДляПоиска Тогда
					Поле.СписокВыбора.Добавить(ДанныеАдреса.Значение, ДанныеАдреса.Значение.Представление);
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
		
		ОбщееКоличествоКоманд = ОбщееКоличествоКоманд + КоличествоКомандВПодменю;
	КонецЦикла;
	
КонецПроцедуры

Процедура ДобавитьКнопкуСкопироватьАдрес(Форма, ИмяКоманды, ЗаголовокЭлемента, ПараметрыКонтактнойИнформации, Подменю)
	
	ИмяЭлемента = Подменю.Имя + "_" + ИмяКоманды;
	Кнопка = Форма.Элементы.Найти(ИмяЭлемента);
	Если Кнопка = Неопределено Тогда
		Кнопка = Форма.Элементы.Добавить(ИмяЭлемента, Тип("КнопкаФормы"), Подменю);
		Кнопка.ИмяКоманды = ИмяКоманды;
		ДобавленныеЭлементы = ПараметрыКонтактнойИнформации.ДобавленныеЭлементы; // СписокЗначений
		ДобавленныеЭлементы.Добавить(ИмяЭлемента, 1);
	КонецЕсли;
	Кнопка.Заголовок = ЗаголовокЭлемента;
	Кнопка.Видимость = ЗначениеЗаполнено(ЗаголовокЭлемента);

КонецПроцедуры

// Конструктор параметра КонтактнаяИнформация для выполнения команд контактной информации
// 
// Параметры:
//   Представление - Строка - представление контактной информации.
//   Значение      - Строка - значение полей контактной информации в формате JSON или XML.
//   Тип           - ПеречислениеСсылка.ТипыКонтактнойИнформации
//   Вид           - СправочникСсылка.ВидыКонтактнойИнформации
//
// Возвращаемое значение:
//   Структура:
//     * Представление - Строка - представление контактной информации.
//     * Значение      - Строка - значение полей контактной информации в формате JSON или XML.
//     * Тип           - ПеречислениеСсылка.ТипыКонтактнойИнформации
//     * Вид           - СправочникСсылка.ВидыКонтактнойИнформации
//
Функция ПараметрКонтактнаяИнформацияДляВыполненияКоманд(Представление, Значение, Тип, Вид)
	
	КонтактнаяИнформация = Новый Структура;
	КонтактнаяИнформация.Вставить("Представление", Представление);
	КонтактнаяИнформация.Вставить("Значение", Значение);
	КонтактнаяИнформация.Вставить("Тип", Тип);
	КонтактнаяИнформация.Вставить("Вид", Вид);

	Возврат КонтактнаяИнформация;
	
КонецФункции

// Конструктор дополнительных параметров для выполнения команд контактной информации
// 
// Параметры:
//   ВладелецКонтактнойИнформации - ОпределяемыйТип.ВладелецКонтактнойИнформации
//   Форма - ФормаКлиентскогоПриложения
//   ИмяРеквизита - Строка
//
// Возвращаемое значение:
//   Структура:
//   * ВладелецКонтактнойИнформации - ОпределяемыйТип.ВладелецКонтактнойИнформации
//   * Форма - ФормаКлиентскогоПриложения
//   * ИмяРеквизита     - Строка - служебный параметр, не предназначен для использования
//   * АсинхронныйВызов - Булево - служебный параметр, не предназначен для использования
//
Функция ДополнительныеПараметрыДляВыполненияКоманд(ВладелецКонтактнойИнформации, Форма, ИмяРеквизита = "", АсинхронныйВызов = Ложь)
	
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("ВладелецКонтактнойИнформации", ВладелецКонтактнойИнформации);
	ДополнительныеПараметры.Вставить("Форма", Форма);
	// Для служебного использования
	ДополнительныеПараметры.Вставить("ИмяРеквизита", ИмяРеквизита);
	ДополнительныеПараметры.Вставить("АсинхронныйВызов", АсинхронныйВызов);

	Возврат ДополнительныеПараметры;
	
КонецФункции

// Параметры:
//   ИмяОбработчика - Строка - полный путь к функции, которую необходимо выполнить.
//                             Например, "_ДемоСтандартныеПодсистемыКлиент.ОткрытьФормуДокументаВстреча".
//   Параметры - Структура:
//     * КонтактнаяИнформация    - см. ПараметрКонтактнаяИнформацияДляВыполненияКоманд
//     * ДополнительныеПараметры - см. ДополнительныеПараметрыДляВыполненияКоманд
//
Процедура ВыполнитьКомандуКонтактнойИнформации(ИмяОбработчика, Параметры)
	
	НачалоИмениПроцедуры = СтрНайти(ИмяОбработчика, ".", НаправлениеПоиска.СКонца);
	
	Если НачалоИмениПроцедуры = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ИмяПроцедуры = СокрЛП(Сред(ИмяОбработчика, НачалоИмениПроцедуры + 1));
	ИмяМодуля = СокрЛП(Лев(ИмяОбработчика, НачалоИмениПроцедуры - 1));
	
	ВыполнитьОбработкуОповещения(Новый ОписаниеОповещения(ИмяПроцедуры, ОбщегоНазначенияКлиент.ОбщийМодуль(ИмяМодуля),
		Параметры.ДополнительныеПараметры), Параметры.КонтактнаяИнформация);	
	
КонецПроцедуры

Процедура ПередТелефоннымЗвонком(КонтактнаяИнформация, ДополнительныеПараметры) Экспорт
	
	Если ПустаяСтрока(КонтактнаяИнформация.Представление) Тогда
		ОбщегоНазначенияКлиент.СообщитьПользователю(
			НСтр("ru = 'Для совершения звонка введите номер телефона.'"), , ДополнительныеПараметры.ИмяРеквизита);
	Иначе
		ПозвонитьПоТелефону(КонтактнаяИнформация.Представление);
	КонецЕсли;
	
КонецПроцедуры

Процедура ПередСозданиемSMS(КонтактнаяИнформация, ДополнительныеПараметры) Экспорт

	Если ПустаяСтрока(КонтактнаяИнформация.Представление) Тогда
		ОбщегоНазначенияКлиент.СообщитьПользователю(
			НСтр("ru = 'Для отправки SMS введите номер телефона.'"), , ДополнительныеПараметры.ИмяРеквизита);
	Иначе
		СоздатьSMS("", КонтактнаяИнформация.Представление, КонтактнаяИнформация.Тип,
			ДополнительныеПараметры.ВладелецКонтактнойИнформации);
	КонецЕсли;

КонецПроцедуры

Процедура ПередЗвонкомНаSkype(КонтактнаяИнформация, ДополнительныеПараметры) Экспорт
	
	ПозвонитьНаSkype(КонтактнаяИнформация.Представление);
	
КонецПроцедуры

Процедура ПередНачаломБеседыВSkype(КонтактнаяИнформация, ДополнительныеПараметры) Экспорт
	
	НачатьБеседуВSkype(КонтактнаяИнформация.Представление);
	
КонецПроцедуры

Процедура ПередПереходомПоВебСсылке(КонтактнаяИнформация, ДополнительныеПараметры) Экспорт
	
	ПерейтиПоВебСсылке("", КонтактнаяИнформация.Представление, КонтактнаяИнформация.Тип);
	
КонецПроцедуры

Процедура ПередСозданиемЭлектронногоПисьма(КонтактнаяИнформация, ДополнительныеПараметры) Экспорт

	СоздатьЭлектронноеПисьмо("", КонтактнаяИнформация.Представление, КонтактнаяИнформация.Тип,
		ДополнительныеПараметры.ВладелецКонтактнойИнформации, ДополнительныеПараметры.ИмяРеквизита);

КонецПроцедуры

Процедура ПередПоказомАдресаНаКартеGoogle(КонтактнаяИнформация, ДополнительныеПараметры) Экспорт
	
	АдресКодированный = ДекодированиеСтроки(КонтактнаяИнформация.Представление);
	СтрокаЗапуска = "https://maps.google.com/?q=" + АдресКодированный;
	ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку(СтрокаЗапуска);
	
КонецПроцедуры

Процедура ПередПоказомАдресаНаКартеЯндекс(КонтактнаяИнформация, ДополнительныеПараметры) Экспорт
	
	АдресКодированный = ДекодированиеСтроки(КонтактнаяИнформация.Представление);
	СтрокаЗапуска = "https://maps.yandex.com/?text=" + АдресКодированный;
	ФайловаяСистемаКлиент.ОткрытьНавигационнуюСсылку(СтрокаЗапуска);
	
КонецПроцедуры

Процедура ПередВводомКомментария(КонтактнаяИнформация, ДополнительныеПараметры) Экспорт
	
	Результат = Новый Структура("ИмяРеквизита", ДополнительныеПараметры.ИмяРеквизита);
	НайденныеСтроки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(
		ДополнительныеПараметры.Форма).НайтиСтроки(Результат);
	Если НайденныеСтроки.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;

	НайденнаяСтрока = НайденныеСтроки[0];
	Результат.Вставить("ИмяЭлементаДляРазмещения", НайденнаяСтрока.ИмяЭлементаДляРазмещения);
	Результат.Вставить("ТипКонтактнойИнформации", НайденнаяСтрока.Тип);
	
	ВвестиКомментарий(ДополнительныеПараметры.Форма, ДополнительныеПараметры.ИмяРеквизита, НайденнаяСтрока, Результат, 
		ДополнительныеПараметры.АсинхронныйВызов);

КонецПроцедуры

Процедура ПередОткрытиемФормыИсторииИзменений(КонтактнаяИнформация, ДополнительныеПараметры) Экспорт
	
	Результат = Новый Структура("ИмяРеквизита", ДополнительныеПараметры.ИмяРеквизита);
	НайденныеСтроки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(
		ДополнительныеПараметры.Форма).НайтиСтроки(Результат);
	Если НайденныеСтроки.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;

	НайденнаяСтрока = НайденныеСтроки[0];
	
	ОткрытьФормуИсторииИзменений(ДополнительныеПараметры.Форма, НайденнаяСтрока, ДополнительныеПараметры.АсинхронныйВызов);
	
КонецПроцедуры

Процедура ПередВыполнениемКомандыИзРасширеннойПодсказкиАдреса(Форма, Элемент, ИмяРеквизита, ИмяКоманды, АсинхронныйВызов)

	Результат = Новый Структура("ИмяРеквизита", ИмяРеквизита);
	НайденныеСтроки = УправлениеКонтактнойИнформациейКлиентСервер.ОписаниеКонтактнойИнформацииНаФорме(
			Форма).НайтиСтроки(Результат);
	Если НайденныеСтроки.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	НайденнаяСтрока          = НайденныеСтроки[0];
	ИмяЭлементаДляРазмещения = НайденнаяСтрока.ИмяЭлементаДляРазмещения;

	ПараметрыКИ = Форма.ПараметрыКонтактнойИнформации[ИмяЭлементаДляРазмещения];
	ВладелецКИ = ПараметрыКИ.Владелец;

	КомандыДляВывода = УправлениеКонтактнойИнформациейКлиентСервер.КомандыДляВыводаНаФорму(ПараметрыКИ,
		НайденнаяСтрока.Тип, НайденнаяСтрока.Вид, НайденнаяСтрока.ХранитьИсториюИзменений);

	КонтактнаяИнформация = ПараметрКонтактнаяИнформацияДляВыполненияКоманд(НайденнаяСтрока.Представление, 
		НайденнаяСтрока.Значение, НайденнаяСтрока.Тип, НайденнаяСтрока.Вид);
	ДополнительныеПараметры = ДополнительныеПараметрыДляВыполненияКоманд(ВладелецКИ, Форма, ИмяРеквизита, АсинхронныйВызов);
	Параметры = Новый Структура("КонтактнаяИнформация, ДополнительныеПараметры", КонтактнаяИнформация,
		ДополнительныеПараметры);

	Если ИмяКоманды = "ПоказатьНаКарте" Тогда
		Список = Новый СписокЗначений;
		ПоказатьНаКартеЯндекс = КомандыДляВывода.ПоказатьНаКартеЯндекс;
		Список.Добавить(ПоказатьНаКартеЯндекс.Действие, ПоказатьНаКартеЯндекс.Заголовок, ,
			ПоказатьНаКартеЯндекс.Картинка);
		ПоказатьНаКартеGoogle = КомандыДляВывода.ПоказатьНаКартеGoogle;
		Список.Добавить(ПоказатьНаКартеGoogle.Действие, ПоказатьНаКартеGoogle.Заголовок, ,
			ПоказатьНаКартеGoogle.Картинка);
		ОповещениеМеню = Новый ОписаниеОповещения("ПослеВыбораИзМеню", ЭтотОбъект, Параметры);
		Форма.ПоказатьВыборИзМеню(ОповещениеМеню, Список, Элемент);
	Иначе
		Если КомандыДляВывода.Свойство(ИмяКоманды) Тогда
			ВыполнитьКомандуКонтактнойИнформации(КомандыДляВывода[ИмяКоманды].Действие, Параметры);
		КонецЕсли;
	КонецЕсли;

КонецПроцедуры

// Удаляет префикс строки. 
//
// Параметры:
//  ИсходнаяСтрока - Строка
//  Префикс        - Строка
//
// Возвращаемое значение:
//   Строка
//
Функция УдалитьПрефиксСтроки(ИсходнаяСтрока, Префикс)

	Если Не СтрНачинаетсяС(ВРег(ИсходнаяСтрока), ВРег(Префикс)) Тогда
		Возврат ИсходнаяСтрока;
	КонецЕсли;

	ДлинаПрефикса = СтрДлина(Префикс);
	СтрокаБезПрефикса = Сред(ИсходнаяСтрока, ДлинаПрефикса + 1);

	Возврат СтрокаБезПрефикса;

КонецФункции

// Удаляет постфикс строки. 
//
// Параметры:
//  ИсходнаяСтрока - Строка
//  Постфикс       - Строка
//
// Возвращаемое значение:
//  Строка
//
Функция УдалитьПостфиксСтроки(ИсходнаяСтрока, Постфикс)

	Если Не СтрЗаканчиваетсяНа(ВРег(ИсходнаяСтрока), ВРег(Постфикс)) Тогда
		Возврат ИсходнаяСтрока;
	КонецЕсли;

	ДлинаПостфикса = СтрДлина(Постфикс);
	ДлинаСтроки = СтрДлина(ИсходнаяСтрока);
	КоличествоСимволов = ДлинаСтроки - ДлинаПостфикса;
	СтрокаБезПостфикса = Лев(ИсходнаяСтрока, КоличествоСимволов);

	Возврат СтрокаБезПостфикса;

КонецФункции

#КонецОбласти